日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

「最简单」的 Core Data 上手指南

發(fā)布時(shí)間:2023/12/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 「最简单」的 Core Data 上手指南 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文講的是「最簡(jiǎn)單」的 Core Data 上手指南,
  • 原文地址:The Easiest Core Data
  • 原文作者:Alberto De Bortoli
  • 譯文出自:掘金翻譯計(jì)劃
  • 譯者:Zheaoli
  • 校對(duì)者:Kulbear,?cbangchen

在過(guò)去的幾個(gè)月里,我花費(fèi)了大量的時(shí)間在研究 Core Data 之上,我得去處理一個(gè)使用了很多陳舊的代碼,糟糕的 Core Data 以及違反了多線程安全的項(xiàng)目。講真,Core Data 學(xué)習(xí)起來(lái)非常的困難,在學(xué)習(xí) Core Data 的時(shí)候,你肯定會(huì)感到迷惑和一種深深的挫敗感。正是因?yàn)檫@些原因,我決定給出一種超級(jí)簡(jiǎn)單的解決方案。這個(gè)方案的特點(diǎn)就是簡(jiǎn)潔,線程安全,非常易于使用,這個(gè)方案能滿(mǎn)足你大部分對(duì)于 Core Data 的需求。在經(jīng)過(guò)若干次的迭代后,我所設(shè)計(jì)的方案最終成為一個(gè)成熟的方案。

OK,女士們,先生們,現(xiàn)在請(qǐng)?jiān)试S我隆重向您介紹?Skiathos?和?Skopelos。其中?Skiathos?是基于Objective-C?所開(kāi)發(fā)的,而?Skopelos?則基于?Swift?所開(kāi)發(fā)的。這兩個(gè)框架的名字來(lái)源于希臘的兩個(gè)島,在這里,我渡過(guò)了2016年的夏天,同時(shí),在這里完成了兩個(gè)框架的編寫(xiě)工作。

寫(xiě)在前面的話

整個(gè)項(xiàng)目的目的就是能夠讓您以及其簡(jiǎn)便的方式在您的 App 中引入 Core Data。

我們將從如下幾個(gè)方面來(lái)進(jìn)行一個(gè)介紹:

  • CoreDataStack
  • AppStateReactor
  • DALService (Data Access Layer)

CoreDataStack

如果你有過(guò)使用 Core Data 的經(jīng)驗(yàn),那么你應(yīng)該知道創(chuàng)建一個(gè)堆棧是一個(gè)充滿(mǎn)陷阱的過(guò)程。這個(gè)組件是用于創(chuàng)建堆棧(用于管理?Obejct Context?),具體的設(shè)計(jì)說(shuō)明可以參看 Marcus Zarra 所寫(xiě)的這篇文章。

其中一個(gè)和 Magical Record 或者其余第三方插件不同的是,整個(gè)存儲(chǔ)過(guò)程都是在一個(gè)方向上發(fā)起的,可能是從某個(gè)子節(jié)點(diǎn)向下或者向上傳遞來(lái)進(jìn)行持久化儲(chǔ)存。其余的組件允許你創(chuàng)建以?private context?作為父節(jié)點(diǎn)的子節(jié)點(diǎn),這將會(huì)導(dǎo)致?main context?不能被更新,同時(shí)只能通過(guò)通知的方式來(lái)進(jìn)行合并更新。main context?是相對(duì)固定的并與?UI?進(jìn)行了綁定:這樣較為簡(jiǎn)單的方式可以幫助開(kāi)發(fā)者更好的去完成一個(gè) APP 的開(kāi)發(fā)。

AppStateReactor

唔,其實(shí)你可以忽略這一段。這個(gè)組件屬于 CoreDataStack ,在 App 切換至后臺(tái),失去節(jié)點(diǎn),或者即將退出時(shí),它負(fù)責(zé)監(jiān)視相對(duì)應(yīng)的修改,并把其保存。

DALService (Data Access Layer) / (Skiathos/Skopelos)

如果你擁有使用 Core Data 的經(jīng)驗(yàn),那么你也應(yīng)該知道,我們大部分操作都是重復(fù)的,我們經(jīng)常在一個(gè) context 中調(diào)用?performBlock:/performBlockAndWait:?函數(shù),而這個(gè) Context 提供了一個(gè)最終會(huì)調(diào)用save:?作為最終語(yǔ)句的 block 。數(shù)據(jù)庫(kù)的所有操作都是基于 API 中所提供的?read:?和?write:?:這兩個(gè)協(xié)議提供了 CQRS (命令和查詢(xún)分離) 的實(shí)現(xiàn)。用于讀取的代碼塊將在主體中進(jìn)行運(yùn)行(因?yàn)檫@被認(rèn)為是一個(gè)已確定的單個(gè)資源)。用于寫(xiě)入的代碼塊將會(huì)在一個(gè)子線程中運(yùn)行,這樣可以保證實(shí)時(shí)的進(jìn)行數(shù)據(jù)儲(chǔ)存,變化的數(shù)據(jù)將會(huì)在不會(huì)阻塞主線程的情況下通過(guò)異步的方式進(jìn)行儲(chǔ)存。write:completion:方法將會(huì)程序運(yùn)行完后來(lái)對(duì)數(shù)據(jù)的更改進(jìn)行持久化儲(chǔ)存。

換句話說(shuō),寫(xiě)入的數(shù)據(jù)在?main managed object context?和最后持久化過(guò)程中都會(huì)保證其一致性。在 主要管理對(duì)象的?context?中,相應(yīng)的數(shù)據(jù)也能保證其可用性。

Skiathos/Skopelos?是?DALService?的子類(lèi), 這樣可以給這個(gè)組件一個(gè)比較好聽(tīng)的名字。

使用介紹

在使用這一系列組件之前,你首先需要?jiǎng)?chuàng)建一個(gè)類(lèi)型為?Skiathos?的屬性,然后以下面這種方式去初始化它:

1 2 3 self.skiathos = [Skiathos setupInMemoryStackWithDataModelFileName:@"<#datamodelfilename>"]; // or self.skiathos = [Skiathos setupSqliteStackWithDataModelFileName:@"<#datamodelfilename>"];

在使用?Skopelos?時(shí),代碼如下所示:

1 2 3 self.skopelos = SkopelosClient(inMemoryStack: "<#datamodelfilename>") // or self.skopelos = SkopelosClient(sqliteStack: "<#datamodelfilename>")

你可以通過(guò)使用依賴(lài)注入的方式來(lái)在應(yīng)用的其余地方使用這些對(duì)象。不得不說(shuō),為 Core Data 棧上的不同對(duì)象創(chuàng)建單例是一種很不錯(cuò)的做法。當(dāng)然,不斷的創(chuàng)建實(shí)例的開(kāi)銷(xiāo)是十分巨大的。通常來(lái)講,我們不是很推薦使用單例模式。單例模式的測(cè)試性不強(qiáng),在使用過(guò)程中,使用者無(wú)法有效的控制其聲明周期,這樣可能會(huì)違背一些最佳實(shí)踐的編程原則。正是因?yàn)槿绱?#xff0c;在這個(gè)庫(kù)里,我們不推薦使用單例。

由于下面幾個(gè)原因,你在使用時(shí)需要從?Skiathos/Skopelos?進(jìn)行繼承:

  • 創(chuàng)建一個(gè)全局可共享的實(shí)例。
  • 重載?handleError(error: NSError)?方法,以便在你的程序里出現(xiàn)一些錯(cuò)誤時(shí),這個(gè)方法能夠正常的被調(diào)用。

為了創(chuàng)建單例,你應(yīng)該如下面的示例一樣去從?Skiathos/Skopelos?進(jìn)行繼承:

單例

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @interface SkiathosClient : Skiathos + (SkiathosClient *)sharedInstance; @end static SkiathosClient *sharedInstance = nil; @implementation SkiathosClient + (SkiathosClient *)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [self setupSqliteStackWithDataModelFileName:@"<#datamodelfilename>"]; </#datamodelfilename> }); return sharedInstance; } - (void)handleError:(NSError *)error { // clients should do the right thing here NSLog(@"%@", error.description); } @end

或者是

1 2 3 4 5 6 7 class SkopelosClient: Skopelos { static let sharedInstance = Skopelos(sqliteStack: "DataModel") override func handleError(error: NSError) { // clients should do the right thing here print(error.description) } }

讀寫(xiě)操作

寫(xiě)到這里,讓我們同時(shí)看看在一個(gè)標(biāo)準(zhǔn) Core Data 的操作方式和我們組件所提供的方式吧。

標(biāo)準(zhǔn)的讀取姿勢(shì):

1 2 3 4 5 6 7 8 9 10 11 __block NSArray *results = nil; NSManagedObjectContext *context = ...; [context performBlockAndWait:^{ NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:NSStringFromClass(User) inManagedObjectContext:context]; [request setEntity:entityDescription]; NSError *error; results = [context executeFetchRequest:request error:&error]; }]; return results;

標(biāo)準(zhǔn)的寫(xiě)入姿勢(shì):

1 2 3 4 5 6 7 8 9 10 11 12 13 NSManagedObjectContext *context = ...; [context performBlockAndWait:^{ User *user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(User) inManagedObjectContext:context]; user.firstname = @"John"; user.lastname = @"Doe"; NSError *error; [context save:&error]; if (!error) { // continue to save back to the store } }];

Skiathos?中的讀取姿勢(shì):

1 2 3 4 [[SkiathosClient sharedInstance] read:^(NSManagedObjectContext *context) { NSArray *allUsers = [User allInContext:context]; NSLog(@"All users: %@", allUsers); }];

Skiathos?中的寫(xiě)入姿勢(shì):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // Sync [[SkiathosClient sharedInstance] writeSync:^(NSManagedObjectContext *context) { User *user = [User createInContext:context]; user.firstname = @"John"; user.lastname = @"Doe"; }]; [[SkiathosClient sharedInstance] writeSync:^(NSManagedObjectContext *context) { User *user = [User createInContext:context]; user.firstname = @"John"; user.lastname = @"Doe"; } completion:^(NSError *error) { // changes are saved to the persistent store }]; // Async [[SkiathosClient sharedInstance] writeAsync:^(NSManagedObjectContext *context) { User *user = [User createInContext:context]; user.firstname = @"John"; user.lastname = @"Doe"; }]; [[SkiathosClient sharedInstance] writeAsync:^(NSManagedObjectContext *context) { User *user = [User createInContext:context]; user.firstname = @"John"; user.lastname = @"Doe"; } completion:^(NSError *error) { // changes are saved to the persistent store }];

Skiathos?當(dāng)然也支持鏈?zhǔn)秸{(diào)用:

1 2 3 4 5 6 7 8 9 10 11 __block User *user = nil; [SkiathosClient sharedInstance].write(^(NSManagedObjectContext *context) { user = [User createInContext:context]; user.firstname = @"John"; user.lastname = @"Doe"; }).write(^(NSManagedObjectContext *context) { User *userInContext = [user inContext:context]; [userInContext deleteInContext:context]; }).read(^(NSManagedObjectContext *context) { NSArray *users = [User allInContext:context]; });

如果是在 Swift中,代碼將會(huì)變成下面這個(gè)樣子

讀取:

1 2 3 4 SkopelosClient.sharedInstance.read { context in let users = User.SK_all(context) print(users) }

寫(xiě)入:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // Sync SkopelosClient.sharedInstance.writeSync { context in let user = User.SK_create(context) user.firstname = "John" user.lastname = "Doe" } SkopelosClient.sharedInstance.writeSync({ context in let user = User.SK_create(context) user.firstname = "John" user.lastname = "Doe" }, completion: { (error: NSError?) in // changes are saved to the persistent store }) // Async SkopelosClient.sharedInstance.writeAsync { context in let user = User.SK_create(context) user.firstname = "John" user.lastname = "Doe" } SkopelosClient.sharedInstance.writeAsync({ context in let user = User.SK_create(context) user.firstname = "John" user.lastname = "Doe" }, completion: { (error: NSError?) in // changes are saved to the persistent store })

鏈?zhǔn)秸{(diào)用:

1 2 3 4 5 6 7 8 9 10 11 12 SkopelosClient.sharedInstance.write { context in user = User.SK_create(context) user.firstname = "John" user.lastname = "Doe" }.write { context in if let userInContext = user.SK_inContext(context) { userInContext.SK_remove(context) } }.read { context in let users = User.SK_all(context) print(users) }

NSManagedObject?類(lèi)所提供了非常清楚的?CRUD?方法。在作為讀/寫(xiě)代碼塊的參數(shù)傳遞之時(shí),對(duì)象應(yīng)該被作為一個(gè)整體進(jìn)行處理。你應(yīng)該優(yōu)先使用這些內(nèi)建的方法。主要的方法有下面這些:

1 2 3 4 5 6 7 + (instancetype)SK_createInContext:(NSManagedObjectContext *)context; + (NSUInteger)SK_numberOfEntitiesInContext:(NSManagedObjectContext *)context; - (void)SK_deleteInContext:(NSManagedObjectContext *)context; + (void)SK_deleteAllInContext:(NSManagedObjectContext *)context; + (NSArray *)SK_allInContext:(NSManagedObjectContext *)context; + (NSArray *)SK_allWithPredicate:(NSPredicate *)pred inContext:(NSManagedObjectContext *)context; + (instancetype)SK_firstInContext:(NSManagedObjectContext *)context;
1 2 3 4 5 6 7 static func SK_create(context: NSManagedObjectContext) -> Self static func SK_numberOfEntities(context: NSManagedObjectContext) -> Int func SK_remove(context: NSManagedObjectContext) -> Void static func SK_removeAll(context: NSManagedObjectContext) -> Void static func SK_all(context: NSManagedObjectContext) -> [Self] static func SK_all(predicate: NSPredicate, context:NSManagedObjectContext) -> [Self] static func SK_first(context: NSManagedObjectContext) -> Self?

注意,在使用?SK_inContext(context: NSManagerObjectContext)?時(shí),不同的讀寫(xiě)代碼塊可能會(huì)得到同一個(gè)對(duì)象。

線程安全

所有 DALService 所產(chǎn)生的實(shí)例都可以認(rèn)為是線程安全的。

我們特別建議你在項(xiàng)目中進(jìn)行這樣的設(shè)置?-com.apple.CoreData.ConcurrencyDebug 1?,這可以確保你不會(huì)在多線程和并發(fā)的情況下濫用 Core Data。

這個(gè)組件不是為了通過(guò)隱藏?ManagedObjectContext:?的概念來(lái)達(dá)到接口引入的目的:它將會(huì)在客戶(hù)端中引入更多的線程問(wèn)題,因?yàn)殚_(kāi)發(fā)者有責(zé)任去檢查所調(diào)用線程的類(lèi)型(而那將會(huì)是在忽視 Core Data 所帶給我們的好處)。





原文發(fā)布時(shí)間為:2016年09月10日
本文來(lái)自云棲社區(qū)合作伙伴掘金,了解相關(guān)信息可以關(guān)注掘金網(wǎng)站。

總結(jié)

以上是生活随笔為你收集整理的「最简单」的 Core Data 上手指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。