2014年3月21日更新:我找到了解决此处所述问题的方法。我创建了一个名为downloadContext的独立NSManagedObjectContext。下载的序列化对象放在单独的上下文中。然后我遍历响应数组并检查对象是否已经存在于MR_defaultContext中(使用主键)。 如果是,我使用相同的主键更新下载对象的属性。不可能简单地复制整个对象,从而覆盖现有对象的所有属性(因为更新的对象和旧对象在不同的上下文中)。相反,我将下载对象的所有属性复制到NSDictionary(dictionaryWithValuesForKeys)中,然后使用setValuesForKeysWithDictionary覆盖旧对象的属性。必须对子对象进行相同的操作。 如果对象是新的,我创建一个新对象并以相同的方式复制属性。我需要检查这个解决方案是否足够有效,或者如果有许多对象要下载(第一次同步),它将占用太多内存。另一种方法是创建我自己的序列化器,该序列化器根据主键决定是更新现有对象还是创建新对象。
对于这个问题,请注意我已经看到了对relatedByAttribute键设置的讨论。在这种情况下它没有帮助,因为这可能只避免重复的子关系对象(我没有检查是否有重复)。这是关于父对象重复。
在我的项目中,我将AFNetworking,MMRecord和MagicalRecord一起用作依赖项。情况如下:
我从AFMMRecordResponseSerializer类创建一个响应序列化器,我只是将其设置为AFHTTPSessionManager的子类对象。使用此会话管理器,我向服务器发送GET请求。响应对象已经包含序列化的NSManagedObjects(它们实际上是MMRecord的子类)。我已将MMRecordEntityPrimaryAttributeKey设置为每个NSManagedObject的预期主键。我认为问题在于MagicalRecords,因为它只是忽略了MMrecord的主要属性键设置。
在持久存储仍为空的初始GET请求之后,没有修改/创建日期谓词。如果已存在持久对象,则GET请求包含一个谓词,该谓词仅从服务器检索最后一个mod日期之后的对象。因此更新的对象是持久的,但旧的对象不会被覆盖。当我在表视图中显示对象的标题时,我可以看到显示对象的旧版本和更新版本。要点:表视图仅从核心数据填充,而不是直接从responseObject(包含序列化对象)填充。 以下是最重要的代码。 感谢您提供正确方向的任何提示 多米尼克
-(void) fetchNotesFromServer
{
NSLog(@"fetchNotesFromServer called");
self.sessionManager.responseSerializer = [self getSerializerForEntityName:@"NAS_Notes" AndEndPointPathComponent:@"DBFetchNotes.php?"];
[self.sessionManager GET:[self getFetchNotesExtension] parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject)
{
if (responseObject )
{
NSLog(@"fetch all notes response: %@", responseObject);
self.latestNotes = (NSMutableArray *)responseObject;
if ([self.latestNotes count] > 0)
{
[self saveDownloadedNotesInContext:[NSManagedObjectContext MR_defaultContext]];
}
}
} failure:^(NSURLSessionDataTask *task, NSError *error)
{
NSLog(@"NSerror %@", error);
}];}
-(void) saveDownloadedNotesInContext:(NSManagedObjectContext *)context{
[context MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
if (success) {
[self.delegate didFinishNotesSync:self];
}
else if (error) {
NSLog(@"error saving to persistent store %@", error);
}
}];
}