5

我的應用程序中有一些效率低下,我想了解並修復。核心數據模式:如何有效更新本地信息與網絡的變化?

我的算法是:

fetch object collection from network 
for each object: 
    if (corresponding locally stored object not found): -- A 
    create object 
    if (a nested related object locally not found): -- B 
     create a related object 

我通過創建與相關對象的主要謂詞查詢這是我的架構的一部分做對線A和B的檢查。我看到,無論A(總是)和B(如果執行分支到該部分)生成SQL選擇,如:

2010-02-05 01:57:51.092 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE1 t0 WHERE t0.ZID = ? 
2010-02-05 01:57:51.097 app[393:207] CoreData: annotation: sql connection fetch time: 0.0046s 
2010-02-05 01:57:51.100 app[393:207] CoreData: annotation: total fetch execution time: 0.0074s for 0 rows. 
2010-02-05 01:57:51.125 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE2 t0 WHERE t0.ZID = ? 
2010-02-05 01:57:51.129 app[393:207] CoreData: annotation: sql connection fetch time: 0.0040s 
2010-02-05 01:57:51.132 app[393:207] CoreData: annotation: total fetch execution time: 0.0071s for 0 rows. 

0.0071s的查詢是3GS設備上很好,但如果你添加的這100你只需要一個700毫秒的阻擋器。

在我的代碼,我使用了一個幫手做這些抓取:

- (MyObject *) myObjectById:(NSNumber *)myObjectId { 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    [fetchRequest setEntity:[self objectEntity]]; // my entity cache  
    [fetchRequest setPredicate:[self objectPredicateById:objectId]]; // predicate cache  
    NSError *error = nil; 
    NSArray *fetchedObjects = [moc executeFetchRequest:fetchRequest error:&error]; 
    if ([fetchedObjects count] == 1) { 
     [fetchRequest release]; 
     return [fetchedObjects objectAtIndex:0]; 
    } 
    [fetchRequest release]; 
    return nil; 
} 

MyObject *obj = [self myObjectById]; 
if (!obj) { 
    // [NSEntityDescription insertNewObjectForEntityForName: ... etc 
} 

我覺得這是不對的,我應該做的檢查一些其他的方式。它應該只打一次數據庫,然後應該來自內存,對吧? (即使對於我知道的對象,SQL也會被執行,這些對象肯定存在於本地,並且應該用前面的查詢加載到內存中。)但是,如果我只有來自外部源的myObjectId,這是我能想到的最好的。因此,也許問題是:如果我有MyObjectId(MyObject上的Core Data int64屬性),我應該如何正確檢查相關本地對象是否存在於CD存儲中?預加載整組可能的匹配,然後預測本地數組?除了當我從線程獲取更改並執行[moc mergeChangesFromContextDidSaveNotification:aNotification];(通過後臺線程獲取已更改的對象的方式)之外,可能的解決方法是將其移動到後臺線程。通知),這仍然會阻止。)

回答

9

閱讀「實現查找 - 或 - 創建高效」核心數據編程指南中。

基本上你需要創建一個ID或屬性的數組,如名稱或任何你從託管對象實體。

然後,您需要創建一個謂詞來使用此數組過濾託管對象。

[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(objectID IN %@)", objectIDs]]; 

當然,「objectIDs」可以是任何可以用來識別的東西。它不一定是NSManagedObjectID。

然後,您可以執行一個獲取請求,並對得到的獲取對象進行迭代以查找重複項。如果不存在,請添加一個新的。

+0

鏈接?我已閱讀http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html上的「核心數據編程指南」,但我不記得有關查找或創建的信息。 – Jaanus 2010-02-05 20:28:26

+6

這裏是鏈接http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174 – 2010-02-05 22:41:42

+1

我標記了這個作爲答案,因爲它與其他幾個(緩存相關的標識符屬性)具有相同的想法,但具有鏈接到官方文檔的附加獎勵。查找或創建正是這樣。 /至於我自己,由於我的數據很小,我最終只是將整個對象集提取到內存中,因爲數據足夠小,我需要最終訪問它,而這種緩存方式非常快。 – Jaanus 2010-02-06 06:07:15

3

你也許可以從電子郵件客戶端上一堂課。

他們通過首先查詢服務器的消息ID列表來工作。一旦客戶端擁有該列表,它就會與本地數據存儲進行比較,以查看是否有任何不同。

如果存在差異,則需要執行幾個操作之一。 1.如果它存在於客戶端,但不是服務器,我們是IMAP,則在本地刪除。 2.如果它存在於服務器上,但不在客戶端上,則下載該消息的其餘部分。

在你的情況下,首先查詢所有的ID。然後發送後續查詢以獲取您尚未擁有的所有數據。

如果您遇到記錄可能存在於本地但可能自上次在服務器上下載後已更新的情況,那麼您的查詢應包含上次更新的日期。

+0

查詢服務器的價格便宜,我和異步完成。我的問題是,「查詢所有本地ID」部分是低效的和/或我不知道如何正確地做到這一點。從網絡 – Jaanus 2010-02-05 18:07:56

1

聽起來像你需要的是NSManagedObjectIDs的NSSet,它被加載到內存或存儲在比你的持久對象存儲更快訪問的地方。

通過這種方式,您可以將網絡中的對象ID與緩存中的對象ID進行比較,而無需在大型數據集上執行獲取請求。

也許從您的託管實體類中的-awakeFromInsert中將ID添加到緩存中?

+0

對象有不同的NSNumber「ID」不與NSManagedObjectID有關。這是我在示例中使用的屬性。所以,只是NSManagedObjectID-s的NSSet是不夠的,因爲我沒有「外部ID-> managedId」映射。 – Jaanus 2010-02-05 18:26:54