问题
Following AlexEdge Tutorial I have encountered the following behavior. I can provide code as requested since there are many lines and I'm not really sure where to look. Basically, it "works" in the sense that the data is properly loaded into the UITableView, but after stopping and starting up the simulator, it inserts new duplicate rows in each section.
I figured this would have something to do with caching but I am following the above tutorial pretty closely and I've set the identificationAttributes
to identify unique records (wouldn't, for example, adding ALL attributes effectively eliminate the possibility that I've not specified a sufficiently unique key, just for debugging purposes?). I've tried changing the Cache name, setting it nil, but it keeps inserting duplicates. Every so often I reset the simulator just to start on a clean slate.
If it matters, I am calling getObjectsAtPath
in viewDidLoad
as per the tutorial. My understanding of how RestKit worked was that it was okay to do so because it would be smart enough to infer that no updates were necessary as the records are all the same.
Edit
I have set identificationAttributes
to an array of two integer attributes that really do determine a unique record.
I also have a managedObjectCache
:
// Seal the deal
[managedStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"CCTDB.sqlite"];
NSError *error;
NSPersistentStore *persistentStore =
[managedStore
addSQLitePersistentStoreAtPath:storePath
fromSeedDatabaseAtPath:nil
withConfiguration:nil
options:@{
NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES
}
error:&error];
NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);
[managedStore createManagedObjectContexts];
managedStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedStore.persistentStoreManagedObjectContext];
EDIT 1
Here is the log output of the second time around
(2013-07-11 03:18:29.961 cocoaclinical[18773:3d07] D restkit.object_mapping:RKPropertyInspector.m:130 Cached property inspection for Class 'EMDisease': {
diseaseId = {
isPrimitive = 0;
keyValueCodingClass = NSNumber;
name = diseaseId;
};
diseaseIdValue = {
isPrimitive = 1;
keyValueCodingClass = NSNumber;
name = diseaseIdValue;
};
name = {
isPrimitive = 0;
keyValueCodingClass = NSString;
name = name;
};
subDiseaseId = {
isPrimitive = 0;
keyValueCodingClass = NSNumber;
name = subDiseaseId;
};
subDiseaseIdValue = {
isPrimitive = 1;
keyValueCodingClass = NSNumber;
name = subDiseaseIdValue;
};
}
2013-07-11 03:18:29.975 cocoaclinical[18773:3f03] I restkit.core_data:RKInMemoryManagedObjectCache.m:94 Caching instances of Entity 'EMDisease' by attributes 'diseaseId, subDiseaseId'
2013-07-11 03:18:29.983 cocoaclinical[18773:3f03] T restkit.core_data:RKInMemoryManagedObjectCache.m:127 Cached 31 objects
2013-07-11 03:18:29.984 cocoaclinical[18773:3f03] D restkit.object_mapping:RKMapperOperation.m:231 Asked to map source object {
DiseaseSystemIdMember = 161;
DisplayNameMember = "Acute Lymphocytic Leukemia";
SubDiseaseSystemIdMember = 1886;
} with mapping <RKEntityMapping:0x96c2850 objectClass=EMDisease propertyMappings=(
"<RKAttributeMapping: 0x96ba060 SubDiseaseSystemIdMember => subDiseaseId>",
"<RKAttributeMapping: 0xb58df40 DisplayNameMember => name>",
"<RKAttributeMapping: 0xb58df70 DiseaseSystemIdMember => diseaseId>"
)>
2013-07-11 03:18:29.984 cocoaclinical[18773:3f03] D restkit.object_mapping:RKMappingOperation.m:952 Starting mapping operation...
2013-07-11 03:18:29.985 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:953 Performing mapping operation: <RKMappingOperation 0xb5b7820> for 'EMDisease' object. Mapping values from object {
DiseaseSystemIdMember = 161;
DisplayNameMember = "Acute Lymphocytic Leukemia";
SubDiseaseSystemIdMember = 1886;
} to object <EMDisease: 0xb5b7ee0> (entity: EMDisease; id: 0xb5b7f80 <x-coredata:///EMDisease/t8DD8EE18-C798-468F-9E03-C6A3C724AA772> ; data: {
diseaseId = 161;
name = nil;
subDiseaseId = 1886;
}) with object mapping (null)
2013-07-11 03:18:30.027 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'SubDiseaseSystemIdMember' to 'subDiseaseId'
2013-07-11 03:18:30.028 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:583 Skipped mapping of attribute value from keyPath 'SubDiseaseSystemIdMember to keyPath 'subDiseaseId' -- value is unchanged (1886)
2013-07-11 03:18:30.029 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'DisplayNameMember' to 'name'
2013-07-11 03:18:30.029 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'DisplayNameMember' to 'name'. Value: Acute Lymphocytic Leukemia
2013-07-11 03:18:30.030 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'DiseaseSystemIdMember' to 'diseaseId'
2013-07-11 03:18:30.030 cocoaclinical[18773:3f03] T restkit.object_mapping:RKMappingOperation.m:583 Skipped mapping of attribute value from keyPath 'DiseaseSystemIdMember to keyPath 'diseaseId' -- value is unchanged (161)
2013-07-11 03:18:30.031 cocoaclinical[18773:3f03] D restkit.object_mapping:RKMappingOperation.m:1021 Finished mapping operation successfully...
回答1:
You do need to set identificationAttributes
, generally only one or two attributes though, not everything. Your entities should have some unique identifier.
You also want to add a managedObjectCache
to your managed object store. This is the part that allows RestKit to match objects using your identificationAttributes
and update the existing items instead of creating new ones.
来源:https://stackoverflow.com/questions/17586880/restkit-core-data-inserts-duplicate-values-in-a-uitableview-on-every-app-laun