2011-10-09 34 views
3

我的iOS項目的一部分輪詢服務器的對象集,然後轉換並保存到核心數據,然後用結果更新UI。服務器任務發生在我稱爲'服務'的NSOperation類的集合中,後者在後臺運行。如果NSManagedObject及其~Context是線程安全的,我將不得不在服務調用主線程上的委託方法像這樣的:將存儲在後臺的一組Core數據對象傳遞給主線程的方式是什麼?

- (void)service:(NSOperation *)service retrievedObjects:(NSArray *)objects; 

當然you can't pass around NSManagedObjects這樣,所以這種委託方法是註定的。據我所見,有兩種解決方案可以從主線程獲取對象。但我都不喜歡,所以我希望偉大的StackOverflow社區能夠幫助我拿出第三名。

  1. 我可以在主線程上執行NSFetchRequest在新增加或修改的對象拉。問題是核心數據存儲包含更多這些對象,所以我必須添加相當多的冗餘來傳達正確的對象集合。一種方法是將一個屬性添加到像batchID這樣的對象,然後我可以將其傳回給委託,以便知道要獲取什麼。但是,向商店添加數據以修復我的併發限制感覺不對。

  2. 我也可以收集新添加的對象'objectID屬性,將它們放入列表中並將該列表發送給委託方法。不幸的是,我必須填充之後的列表我保存了上下文,這意味着在我擁有正確的列表(第一次是解析服務器響應時)之前,我必須在後臺循環兩次對象。然後,我仍然只有一個objectID s的列表,我必須在主線程中使用中的existingObjectWithID:error:個別捲入。這看起來很麻煩。

我錯過了哪些信息?第三個解決方案是從後臺線程將一組NSManagedObject帶到主線程,而不會丟失線程限制?

回答

0

epologee,

雖然你明明有一個解決方案你是幸福的,我建議你失去一些有價值的信息,物品是否被更新,刪除或插入,用你的機制。在我的代碼中,我只是將userInfo字典遷移到新的MOC。這裏是一個通用的程序可以這樣做:

// Migrate a userInfo dictionary as defined by NSManagedObjectContextDidSaveNotification 
// to the receiver context. 
- (NSDictionary *) migrateUserInfo: (NSDictionary *) userInfo { 

    NSMutableDictionary *ui = [NSMutableDictionary dictionaryWithCapacity: userInfo.count]; 

    NSSet  * sourceSet = nil; 
    NSMutableSet *migratedSet = nil; 

    for (NSString *key in [userInfo allKeys]) { 

     sourceSet = [userInfo valueForKey: key]; 
     migratedSet = [NSMutableSet setWithCapacity: sourceSet.count]; 

     for (NSManagedObject *mo in sourceSet) { 

      [migratedSet addObject: [self.moc objectWithID: mo.objectID]]; 
     } 
     [ui setValue: migratedSet forKey: key]; 
    } 
    return ui; 

} // -migrateUserInfo: 

上述例程假定它是具有一個@property NSManagedObjectContext *moc一類的方法。

我希望你能找到以上有用的東西。

Andrew

+0

我喜歡這個解決方案,謝謝!你實際上得到了「回答」的標誌,因爲它比我的更適合一般用途。謝謝@adonoho! – epologee

0

核心數據編程指南中的一部分地址爲Concurrency with Core Data。簡而言之,每個線程應該有自己的託管對象上下文,然後use notifications來同步上下文。

+0

嗨Caleb,感謝您花時間。我正在使用'NSManagedObjectContextDidSaveNotification'將它傳遞給'mergeChangesFromContextDidSaveNotification:'並重新獲得主線程上下文同步,但是我不應該自己戳那個通知的內容嗎?我被困在檢索從服務器到主線程的確切對象集。 – epologee

0

經過一些實驗後,我決定對我提出的方法編號進行一些細微的修改。在對上下文執行背景更改時,請將要委派的對象分數返回主線程,例如一個NSMutableArray *objectsOfInterest。我們最終想要獲取此數組中所有對象的objectID鍵,但是因爲在保存上下文時objectID值發生了變化,所以我們首先必須執行該[context save:&error]。保存之後,請使用以下的NSArray類arrayFromObjectsAtKey:方法生成objectID實例的列表,像這樣:

NSArray *objectIDs = [objectsOfInterest arrayFromObjectsAtKey:@"objectID"]; 

這陣就可以傳回安全地通過委託主線程(一定要確保您的主線索上下文將更新爲mergeChangesFromContextDidSaveNotification,方法是收聽NSManagedObjectContextDidSaveNotification)。當您準備捲入後臺操作的對象時,請使用以下類別中的existingObjectsWithIDs:error:方法將objectID的數組轉換回工作列表NSManagedObject s。

任何意見,以改善這些方法的簡潔或性能表示讚賞。

@implementation NSArray (Concurrency) 

- (NSArray *)arrayFromObjectsAtKey:(NSString *)key { 
    NSMutableArray *objectsAtKey = [NSMutableArray array]; 
    for (id value in self) { 
     [objectsAtKey addObject:[value valueForKey:key]]; 
    } 
    return objectsAtKey; 
} 

@end 

@implementation NSManagedObjectContext (Concurrency) 

- (NSArray *)existingObjectsWithIDs:(NSArray *)objectIDs error:(NSError **)error { 
    NSMutableArray *entities = [NSMutableArray array]; 

    @try { 
     for (NSManagedObjectID *objectID in objectIDs) { 
      // existingObjectWithID might return nil if it can't find the objectID, but if you're not prepared for this, 
      // don't use this method but write your own. 
      [entities addObject:[self existingObjectWithID:objectID error:error]]; 
     } 
    } 
    @catch (NSException *exception) { 
     return nil; 
    } 

    return entities; 
} 

@end 
相關問題