認識CoreData - 多線程

該文章屬于劉小壯原創(chuàng),轉(zhuǎn)載請注明:劉小壯

配圖

CoreData使用相關(guān)的技術(shù)點已經(jīng)講差不多了蹄皱,我所掌握的也就這么多了....

在本篇文章中主要講CoreData的多線程所森,其中會包括并發(fā)隊列類型囱持、線程安全等技術(shù)點。我對多線程的理解可能不是太透徹焕济,文章中出現(xiàn)的問題還請各位指出纷妆。在之后公司項目使用CoreData的過程中,我會將其中遇到的多線程相關(guān)的問題更新到文章中晴弃。

在文章的最后掩幢,會根據(jù)我對CoreData多線程的學(xué)習(xí),以及在工作中的具體使用上鞠,給出一些關(guān)于多線程結(jié)構(gòu)的設(shè)計建議际邻,各位可以當(dāng)做參考。

文章中如有疏漏或錯誤芍阎,還請各位及時提出世曾,謝謝!??


MOC并發(fā)隊列類型

CoreDataMOC是支持多線程的谴咸,可以在創(chuàng)建MOC對象時轮听,指定其并發(fā)隊列的類型。當(dāng)指定隊列類型后岭佳,系統(tǒng)會將操作都放在指定的隊列中執(zhí)行血巍,如果指定的是私有隊列,系統(tǒng)會創(chuàng)建一個新的隊列珊随。但這都是系統(tǒng)內(nèi)部的行為述寡,我們并不能獲取這個隊列,隊列由系統(tǒng)所擁有叶洞,并由系統(tǒng)將任務(wù)派發(fā)到這個隊列中執(zhí)行的鲫凶。

NSManagedObjectContext并發(fā)隊列類型:
  • NSConfinementConcurrencyType : 如果使用init方法初始化上下文,默認就是這個并發(fā)類型衩辟。這個枚舉值是不支持多線程的掀序,從名字上也體現(xiàn)出來了。

  • NSPrivateQueueConcurrencyType : 私有并發(fā)隊列類型惭婿,操作都是在子線程中完成的。

  • NSMainQueueConcurrencyType : 主并發(fā)隊列類型叶雹,如果涉及到UI相關(guān)的操作财饥,應(yīng)該考慮使用這個枚舉值初始化上下文。

其中NSConfinementConcurrencyType類型在iOS9之后已經(jīng)被蘋果廢棄折晦,不建議使用這個API钥星。使用此類型創(chuàng)建的MOC挤巡,調(diào)用某些比較新的CoreDataAPI可能會導(dǎo)致崩潰钟病。

MOC多線程調(diào)用方式

CoreDataMOC不是線程安全的授翻,在多線程情況下使用MOC時去扣,不能簡單的將MOC從一個線程中傳遞到另一個線程中使用,這并不是CoreData的多線程宁改,而且會出問題缕探。對于MOC多線程的使用,蘋果給出了自己的解決方案还蹲。

在創(chuàng)建的MOC中使用多線程爹耗,無論是私有隊列還是主隊列,都應(yīng)該采用下面兩種多線程的使用方式谜喊,而不是自己手動創(chuàng)建線程潭兽。調(diào)用下面方法后,系統(tǒng)內(nèi)部會將任務(wù)派發(fā)到不同的隊列中執(zhí)行斗遏∩截裕可以在不同的線程中調(diào)用MOC的這兩個方法,這個是允許的诵次。

- (void)performBlock:(void (^)())block            異步執(zhí)行的block账蓉,調(diào)用之后會立刻返回。
- (void)performBlockAndWait:(void (^)())block     同步執(zhí)行的block藻懒,調(diào)用之后會等待這個任務(wù)完成剔猿,才會繼續(xù)向下執(zhí)行。

下面是多線程調(diào)用的示例代碼嬉荆,在多線程的環(huán)境下執(zhí)行MOCsave方法归敬,就是將save方法放在MOCblock體中異步執(zhí)行,其他方法的調(diào)用也是一樣的鄙早。

[context performBlock:^{
    [context save:nil];
}];

但是需要注意的是汪茧,這兩個block方法不能在NSConfinementConcurrencyType類型的MOC下調(diào)用,這個類型的MOC是不支持多線程的限番,只支持其他兩種并發(fā)方式的MOC舱污。

多線程的使用

在業(yè)務(wù)比較復(fù)雜的情況下,需要進行大量數(shù)據(jù)處理弥虐,并且還需要涉及到UI的操作扩灯。對于這種復(fù)雜需求,如果都放在主隊列中霜瘪,對性能和界面流暢度都會有很大的影響珠插,導(dǎo)致用戶體驗非常差,降低屏幕FPS颖对。對于這種情況捻撑,可以采取多個MOC配合的方式。

CoreData多線程的發(fā)展中,在iOS5經(jīng)歷了一次比較大的變化顾患,之后可以更方便的使用多線程番捂。從iOS5開始,支持設(shè)置MOCparentContext屬性江解,通過這個屬性可以設(shè)置MOC父MOC设预。下面會針對iOS5之前和之后,分別講解CoreData的多線程使用膘流。

盡管現(xiàn)在的開發(fā)中早就不兼容iOS5之前的系統(tǒng)了絮缅,但是作為了解這里還是要講一下,而且這種同步方式在iOS5之后也是可以正常使用的呼股,也有很多人還在使用這種同步方式耕魄,下面其他章節(jié)也是同理。

iOS5之前使用多個MOC

iOS5之前實現(xiàn)MOC的多線程彭谁,可以創(chuàng)建多個MOC吸奴,多個MOC使用同一個PSC,并讓多個MOC實現(xiàn)數(shù)據(jù)同步缠局。通過這種方式不用擔(dān)心PSC在調(diào)用過程中的線程問題则奥,MOC在使用PSC進行save操作時,會對PSC進行加鎖狭园,等當(dāng)前加鎖的MOC執(zhí)行完操作之后读处,其他MOC才能繼續(xù)執(zhí)行操作。

每一個PSC都對應(yīng)著一個持久化存儲區(qū)唱矛,PSC知道存儲區(qū)中數(shù)據(jù)存儲的數(shù)據(jù)結(jié)構(gòu)罚舱,而MOC需要使用這個PSC進行save操作的實現(xiàn)。

多線程結(jié)構(gòu)

這樣做有一個問題绎谦,當(dāng)一個MOC發(fā)生改變并持久化到本地時管闷,系統(tǒng)并不會將其他MOC緩存在內(nèi)存中的NSManagedObject對象改變。所以這就需要我們在MOC發(fā)生改變時窃肠,將其他MOC數(shù)據(jù)更新包个。

根據(jù)上面的解釋,在下面例子中創(chuàng)建了一個主隊列的mainMOC冤留,主要用于UI操作碧囊。一個私有隊列的backgroundMOC,用于除UI之外的耗時操作纤怒,兩個MOC使用的同一個PSC糯而。

// 獲取PSC實例對象
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    // 創(chuàng)建托管對象模型,并指明加載Company模型文件
    NSURL *modelPath = [[NSBundle mainBundle] URLForResource:@"Company" withExtension:@"momd"];
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelPath];

    // 創(chuàng)建PSC對象肪跋,并將托管對象模型當(dāng)做參數(shù)傳入,其他MOC都是用這一個PSC土砂。
    NSPersistentStoreCoordinator *PSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

    // 根據(jù)指定的路徑州既,創(chuàng)建并關(guān)聯(lián)本地數(shù)據(jù)庫
    NSString *dataPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
    dataPath = [dataPath stringByAppendingFormat:@"/%@.sqlite", @"Company"];
    [PSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:dataPath] options:nil error:nil];

    return PSC;
}

// 初始化用于本地存儲的所有MOC
- (void)createManagedObjectContext {

    // 創(chuàng)建PSC實例對象谜洽,其他MOC都用這一個PSC。
    NSPersistentStoreCoordinator *PSC = self.persistentStoreCoordinator;

    // 創(chuàng)建主隊列MOC吴叶,用于執(zhí)行UI操作
    NSManagedObjectContext *mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    mainMOC.persistentStoreCoordinator = PSC;

    // 創(chuàng)建私有隊列MOC阐虚,用于執(zhí)行其他耗時操作
    NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    backgroundMOC.persistentStoreCoordinator = PSC;

    // 通過監(jiān)聽NSManagedObjectContextDidSaveNotification通知,來獲取所有MOC的改變消息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];
}

// MOC改變后的通知回調(diào)
- (void)contextChanged:(NSNotification *)noti {
    NSManagedObjectContext *MOC = noti.object;
    // 這里需要做判斷操作蚌卤,判斷當(dāng)前改變的MOC是否我們將要做同步的MOC实束,如果就是當(dāng)前MOC自己做的改變,那就不需要再同步自己了逊彭。
    // 由于項目中可能存在多個PSC咸灿,所以下面還需要判斷PSC是否當(dāng)前操作的PSC,如果不是當(dāng)前PSC則不需要同步侮叮,不要去同步其他本地存儲的數(shù)據(jù)避矢。
    [MOC performBlock:^{
        // 直接調(diào)用系統(tǒng)提供的同步API,系統(tǒng)內(nèi)部會完成同步的實現(xiàn)細節(jié)囊榜。
        [MOC mergeChangesFromContextDidSaveNotification:noti];
    }];
}

在上面的Demo中审胸,創(chuàng)建了一個PSC,并將其他MOC都關(guān)聯(lián)到這個PSC上卸勺,這樣所有的MOC執(zhí)行本地持久化相關(guān)的操作時砂沛,都是通過同一個PSC進行操作的。并在下面添加了一個通知曙求,這個通知是監(jiān)聽所有MOC執(zhí)行save操作后的通知碍庵,并在通知的回調(diào)方法中進行數(shù)據(jù)的合并

iOS5之后使用多個MOC

iOS5之后圆到,MOC可以設(shè)置parentContext怎抛,一個parentContext可以擁有多個ChildContext。在ChildContext執(zhí)行save操作后芽淡,會將操作pushparentContext马绝,由parentContext去完成真正的save操作,而ChildContext所有的改變都會被parentContext所知曉挣菲,這解決了之前MOC手動同步數(shù)據(jù)的問題富稻。

需要注意的是,在ChildContext調(diào)用save方法之后白胀,此時并沒有將數(shù)據(jù)寫入存儲區(qū)椭赋,還需要調(diào)用parentContextsave方法。因為ChildContext并不擁有PSC或杠,ChildContext也不需要設(shè)置PSC哪怔,所以需要parentContext調(diào)用PSC來執(zhí)行真正的save操作。也就是只有擁有PSCMOC執(zhí)行save操作后,才是真正的執(zhí)行了寫入存儲區(qū)的操作认境。

- (void)createManagedObjectContext {
    // 創(chuàng)建PSC實例對象胚委,還是用上面Demo的實例化代碼
    NSPersistentStoreCoordinator *PSC = self.persistentStoreCoordinator;

    // 創(chuàng)建主隊列MOC,用于執(zhí)行UI操作
    NSManagedObjectContext *mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    mainMOC.persistentStoreCoordinator = PSC;

    // 創(chuàng)建私有隊列MOC叉信,用于執(zhí)行其他耗時操作亩冬,backgroundMOC并不需要設(shè)置PSC
    NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    backgroundMOC.parentContext = mainMOC;

    // 私有隊列的MOC和主隊列的MOC,在執(zhí)行save操作時硼身,都應(yīng)該調(diào)用performBlock:方法硅急,在自己的隊列中執(zhí)行save操作。
    // 私有隊列的MOC執(zhí)行完自己的save操作后佳遂,還調(diào)用了主隊列MOC的save方法营袜,來完成真正的持久化操作,否則不能持久化到本地
    [backgroundMOC performBlock:^{
        [backgroundMOC save:nil];
    
        [mainMOC performBlock:^{
            [mainMOC save:nil];
        }];
    }];
}

上面例子中創(chuàng)建一個主隊列的mainMOC讶迁,來完成UI相關(guān)的操作连茧。創(chuàng)建私有隊列的backgroundMOC,處理復(fù)雜邏輯以及數(shù)據(jù)處理操作巍糯,在實際開發(fā)中可以根據(jù)需求創(chuàng)建多個backgroundMOC啸驯。需要注意的是,在backgroundMOC執(zhí)行完save方法后祟峦,又在mainMOC中執(zhí)行了一次save方法罚斗,這步是很重要的。

iOS5之前進行數(shù)據(jù)同步

就像上面章節(jié)中講到的宅楞,在iOS5之前存在多個MOC的情況下针姿,一個MOC發(fā)生更改并提交存儲區(qū)后,其他MOC并不知道這個改變距淫,其他MOC和本地存儲的數(shù)據(jù)是不同步的,所以就涉及到數(shù)據(jù)同步的問題婶希。

進行數(shù)據(jù)同步時缴啡,會遇到多種復(fù)雜情況碘裕。例如只有一個MOC數(shù)據(jù)發(fā)生了改變,其他MOC更新時并沒有對相同的數(shù)據(jù)做改變揩页,這樣不會造成沖突旷偿,可以直接將其他MOC更新。

如果在一個MOC數(shù)據(jù)發(fā)生改變后爆侣,其他MOC對相同的數(shù)據(jù)做了改變萍程,而且改變的結(jié)果不同,這樣在同步時就會造成沖突兔仰。下面將會按照這兩種情況茫负,分別講一下不同情況下的沖突處理方式。

簡單情況下的數(shù)據(jù)同步

簡單情況下的數(shù)據(jù)同步乎赴,是針對于只有一個MOC的數(shù)據(jù)發(fā)生改變忍法,并提交存儲區(qū)后,其他MOC更新時并沒有對相同的數(shù)據(jù)做改變榕吼,只是單純的同步數(shù)據(jù)的情況饿序。

NSManagedObjectContext類中,根據(jù)不同操作定義了一些通知羹蚣。在一個MOC發(fā)生改變時原探,其他地方可以通過MOC中定義的通知名,來獲取MOC發(fā)生的改變度宦。在NSManagedObjectContext中定義了下面三個通知:

  • NSManagedObjectContextWillSaveNotification MOC將要向存儲區(qū)存儲數(shù)據(jù)時踢匣,調(diào)用這個通知。在這個通知中不能獲取發(fā)生改變相關(guān)的NSManagedObject對象戈抄。

  • NSManagedObjectContextDidSaveNotification MOC向存儲區(qū)存儲數(shù)據(jù)后离唬,調(diào)用這個通知。在這個通知中可以獲取改變划鸽、添加输莺、刪除等信息戚哎,以及相關(guān)聯(lián)的NSManagedObject對象。

  • NSManagedObjectContextObjectsDidChangeNotificationMOC中任何一個托管對象發(fā)生改變時嫂用,調(diào)用這個通知型凳。例如修改托管對象的屬性。

通過監(jiān)聽NSManagedObjectContextDidSaveNotification通知嘱函,獲取所有MOCsave操作甘畅。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(settingsContext:) name:NSManagedObjectContextDidSaveNotification object:nil];

不需要在通知的回調(diào)方法中,編寫代碼對比被修改的托管對象往弓。MOC為我們提供了下面的方法疏唾,只需要將通知對象傳入,系統(tǒng)會自動同步數(shù)據(jù)函似。

- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification;

下面是通知中的實現(xiàn)代碼槐脏,但是需要注意的是,由于通知是同步執(zhí)行的撇寞,在通知對應(yīng)的回調(diào)方法中所處的線程顿天,和發(fā)出通知的MOC執(zhí)行操作時所處的線程是同一個線程,也就是系統(tǒng)performBlock:回調(diào)方法分配的線程蔑担。

所以其他MOC在通知回調(diào)方法中牌废,需要注意使用performBlock:方法,并在block體中執(zhí)行操作啤握。

- (void)settingsContext:(NSNotification *)noti {
    [context performBlock:^{
        // 調(diào)用需要同步的MOC對象的merge方法畔规,直接將通知對象當(dāng)做參數(shù)傳進去即可,系統(tǒng)會完成同步操作恨统。
        [context mergeChangesFromContextDidSaveNotification:noti];
    }];
}

復(fù)雜情況下的數(shù)據(jù)同步

在一個MOC對本地存儲區(qū)的數(shù)據(jù)發(fā)生改變叁扫,而其他MOC也對同樣的數(shù)據(jù)做了改變,這樣后面執(zhí)行save操作的MOC就會沖突畜埋,并導(dǎo)致后面的save操作失敗莫绣,這就是復(fù)雜情況下的數(shù)據(jù)合并。

這是因為每次一個MOC執(zhí)行一次fetch操作后悠鞍,會保存一個本地持久化存儲的狀態(tài)对室,當(dāng)下次執(zhí)行save操作時會對比這個狀態(tài)和本地持久化狀態(tài)是否一樣。如果一樣咖祭,則代表本地沒有其他MOC對存儲發(fā)生過改變掩宜;如果不一樣,則代表本地持久化存儲被其他MOC改變過么翰,這就是造成沖突的根本原因牺汤。

對于這種沖突的情況,可以通過MOC對象指定解決沖突的方案浩嫌,通過mergePolicy屬性來設(shè)置方案檐迟。mergePolicy屬性有下面幾種可選的策略补胚,默認是NSErrorMergePolicy方式,這也是唯一一個有NSError返回值的選項追迟。

  • NSErrorMergePolicy : 默認值溶其,當(dāng)出現(xiàn)合并沖突時,返回一個NSError對象來描述錯誤敦间,而MOC和持久化存儲區(qū)不發(fā)生改變瓶逃。

  • NSMergeByPropertyStoreTrumpMergePolicy : 以本地存儲為準,使用本地存儲來覆蓋沖突部分廓块。

  • NSMergeByPropertyObjectTrumpMergePolicy : 以MOC的為準金闽,使用MOC來覆蓋本地存儲的沖突部分。

  • NSOverwriteMergePolicy : 以MOC為準剿骨,用MOC的所有NSManagedObject對象覆蓋本地存儲的對應(yīng)對象。

  • NSRollbackMergePolicy : 以本地存儲為準埠褪,MOC所有的NSManagedObject對象被本地存儲的對應(yīng)對象所覆蓋浓利。

上面五種策略中,除了第一個NSErrorMergePolicy的策略钞速,其他四種中NSMergeByPropertyStoreTrumpMergePolicyNSRollbackMergePolicy贷掖,以及NSMergeByPropertyObjectTrumpMergePolicyNSOverwriteMergePolicy看起來是重復(fù)的。

其實它們并不是沖突的渴语,這四種策略的不同體現(xiàn)在苹威,對沒有發(fā)生沖突的部分應(yīng)該怎么處理NSMergeByPropertyStoreTrumpMergePolicyNSMergeByPropertyObjectTrumpMergePolicy對沒有沖突的部分驾凶,未沖突部分數(shù)據(jù)并不會受到影響牙甫。而NSRollbackMergePolicyNSOverwriteMergePolicy則是無論是否沖突,直接全部替換调违。

題外話:
對于MOC的這種合并策略來看窟哺,有木有感覺到CoreData解決沖突的方式,和SVN解決沖突的方式特別像技肩。且轨。。

線程安全

無論是MOC還是托管對象虚婿,都不應(yīng)該在其他MOC的線程中執(zhí)行操作旋奢,這兩個API都不是線程安全的。但MOC可以在其他MOC線程中調(diào)用performBlock:方法然痊,切換到自己的線程執(zhí)行操作至朗。

如果其他MOC想要拿到托管對象,并在自己的隊列中使用托管對象剧浸,這是不允許的爽丹,托管對象是不能直接傳遞到其他MOC的線程的筑煮。但是可以通過獲取NSManagedObjectNSManagedObjectID對象,在其他MOC中通過NSManagedObjectID對象粤蝎,從持久化存儲區(qū)中獲取NSManagedObject對象真仲,這樣就是允許的。NSManagedObjectID是線程安全初澎,并且可以跨線程使用的秸应。

可以通過MOC獲取NSManagedObjectID對應(yīng)的NSManagedObject對象,例如下面幾個MOCAPI碑宴。

NSManagedObject *object = [context objectRegisteredForID:objectID];
NSManagedObject *object = [context objectWithID:objectID];

通過NSManagedObject對象的objectID屬性软啼,獲取NSManagedObjectID類型的objectID對象。

NSManagedObjectID *objectID = object.objectID;

CoreData多線程結(jié)構(gòu)設(shè)計

上面章節(jié)中寫的大多都是怎么用CoreData多線程延柠,在掌握多線程的使用后祸挪,就可以根據(jù)公司業(yè)務(wù)需求,設(shè)計一套CoreData多線程結(jié)構(gòu)了贞间。對于多線程結(jié)構(gòu)的設(shè)計贿条,應(yīng)該本著盡量減少主線程壓力的角度去設(shè)計,將所有耗時操作都放在子線程中執(zhí)行增热。

對于具體的設(shè)計我根據(jù)不同的業(yè)務(wù)需求整以,給出兩種設(shè)計方案的建議。

兩層設(shè)計方案

在項目中多線程操作比較簡單時峻仇,可以創(chuàng)建一個主隊列mainMOC公黑,和一個或多個私有隊列的backgroundMOC。將所有backgroundMOCparentContext設(shè)置為mainMOC摄咆,采取這樣的兩層設(shè)計一般就能夠滿足大多數(shù)需求了凡蚜。

兩層設(shè)計方案

將耗時操作都放在backgroundMOC中執(zhí)行,mainMOC負責(zé)所有和UI相關(guān)的操作吭从。所有和UI無關(guān)的工作都交給backgroundMOC番刊,在backgroundMOC對數(shù)據(jù)發(fā)生改變后,調(diào)用save方法會將改變pushmainMOC中影锈,再由mainMOC執(zhí)行save方法將改變保存到存儲區(qū)芹务。

代碼這里就不寫了,和上面例子中設(shè)置parentContext代碼一樣鸭廷,主要講一下設(shè)計思路枣抱。

三層設(shè)計方案

但是我們發(fā)現(xiàn),上面的save操作最后還是由mainMOC去執(zhí)行的辆床,backgroundMOC只是負責(zé)處理數(shù)據(jù)佳晶。雖然mainMOC只執(zhí)行save操作并不會很耗時,但是如果save涉及的數(shù)據(jù)比較多讼载,這樣還是會對性能造成影響的轿秧。

雖然客戶端很少涉及到大量數(shù)據(jù)處理的需求中跌,但是假設(shè)有這樣的需求」酱郏可以考慮在兩層結(jié)構(gòu)之上漩符,給mainMOC之上再添加一個parentMOC,這個parentMOC也是私有隊列的MOC驱还,用于處理save操作嗜暴。

三層設(shè)計方案

這樣CoreData存儲的結(jié)構(gòu)就是三層了,最底層是backgroundMOC負責(zé)處理數(shù)據(jù)议蟆,中間層是mainMOC負責(zé)UI相關(guān)操作闷沥,最上層也是一個backgroundMOC負責(zé)執(zhí)行save操作。這樣就將影響UI的所有耗時操作全都剝離到私有隊列中執(zhí)行咐容,使性能達到了很好的優(yōu)化舆逃。

需要注意的是,執(zhí)行MOC相關(guān)操作時戳粒,不要阻塞當(dāng)前主線程路狮。所有MOC的操作應(yīng)該是異步的,無論是子線程還是主線程享郊,盡量少的使用同步block方法。

MOC同步時機

設(shè)置MOCparentContext屬性之后孝鹊,parent對于child的改變是知道的炊琉,但是child對于parent的改變是不知道的。蘋果這樣設(shè)計又活,應(yīng)該是為了更好的數(shù)據(jù)同步苔咪。

Employee *emp = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:backgroundMOC];
emp.name = @"lxz";
emp.brithday = [NSDate date];
emp.height = @1.7f;

[backgroundMOC performBlock:^{
    [backgroundMOC save:nil];
    [mainMOC performBlock:^{
        [mainMOC save:nil];
    }];
}];

在上面這段代碼中,mainMOCbackgroundMOCparentContext柳骄。在backgroundMOC執(zhí)行save方法前团赏,backgroundMOCmainMOC都不能獲取到Employee的數(shù)據(jù),在backgroundMOC執(zhí)行完save方法后耐薯,自身上下文發(fā)生改變的同時舔清,也將改變pushmainMOC中,mainMOC也具有了Employee對象曲初。

所以在backgroundMOCsave方法執(zhí)行時体谒,是對內(nèi)存中的上下文做了改變,當(dāng)擁有PSCmainMOC執(zhí)行save方法后臼婆,是對本地存儲區(qū)做了改變抒痒。


好多同學(xué)都問我有Demo沒有,其實文章中貼出的代碼組合起來就是個Demo颁褂。后來想了想故响,還是給本系列文章配了一個簡單的Demo傀广,方便大家運行調(diào)試,后續(xù)會給所有博客的文章都加上Demo彩届。

Demo只是來輔助讀者更好的理解文章中的內(nèi)容伪冰,應(yīng)該博客結(jié)合Demo一起學(xué)習(xí),只看Demo還是不能理解更深層的原理惨缆。Demo中幾乎每一行代碼都會有注釋糜值,各位可以打斷點跟著Demo執(zhí)行流程走一遍,看看各個階段變量的值坯墨。

Demo地址劉小壯的Github


這兩天更新了一下文章寂汇,將CoreData系列的六篇文章整合在一起,做了一個PDF版的《CoreData Book》捣染,放在我Github上了骄瓣。PDF上有文章目錄,方便閱讀耍攘。

如果你覺得不錯榕栏,請把PDF幫忙轉(zhuǎn)到其他群里,或者你的朋友蕾各,讓更多的人了解CoreData扒磁,衷心感謝!??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末式曲,一起剝皮案震驚了整個濱河市妨托,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吝羞,老刑警劉巖兰伤,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異钧排,居然都是意外死亡敦腔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門恨溜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來符衔,“玉大人,你說我怎么就攤上這事糟袁“啬澹” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵系吭,是天一觀的道長五嫂。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么沃缘? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任躯枢,我火速辦了婚禮,結(jié)果婚禮上槐臀,老公的妹妹穿的比我還像新娘锄蹂。我一直安慰自己,他們只是感情好水慨,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布得糜。 她就那樣靜靜地躺著,像睡著了一般晰洒。 火紅的嫁衣襯著肌膚如雪朝抖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天谍珊,我揣著相機與錄音治宣,去河邊找鬼。 笑死砌滞,一個胖子當(dāng)著我的面吹牛侮邀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贝润,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼绊茧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了打掘?” 一聲冷哼從身側(cè)響起华畏,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胧卤,沒想到半個月后唯绍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拼岳,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡枝誊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惜纸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叶撒。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耐版,靈堂內(nèi)的尸體忽然破棺而出祠够,到底是詐尸還是另有隱情,我是刑警寧澤粪牲,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布古瓤,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏落君。R本人自食惡果不足惜穿香,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绎速。 院中可真熱鬧皮获,春花似錦、人聲如沸纹冤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萌京。三九已至雁歌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枫夺,已是汗流浹背将宪。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留橡庞,地道東北人较坛。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像扒最,于是被迫代替她去往敵國和親丑勤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 該文章屬于劉小壯原創(chuàng)吧趣,轉(zhuǎn)載請注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 26,966評論 75 85
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 該文章屬于劉小壯原創(chuàng)法竞,轉(zhuǎn)載請注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 17,006評論 62 62
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,629評論 2 17
  • 小孩子都有一顆好奇的心强挫,老兒還是四五歲的時候岔霸,不知道從哪弄來一蹲馬蘭花苗,栽到了園子的一角并每天澆水俯渤,經(jīng)過一段時間...
    楊成軍閱讀 739評論 5 12