我正在做的一些背景:
我从服务器下载了一个 CSV 文件,其中包含许多小工具的数据。然后使用 CSV 解析器将数据解析为 NSDictionaries 数组。完成后,下面的代码会将字典中保存的信息写入核心数据。
下面的代码在做什么的快速解释:
- 获取所有现有的核心数据项
- 对于每个字典,检查产品代码是否与核心数据中已经存在的代码匹配
- 如果没有匹配,创建一个新的小工具实体并保存它的数据
- 如果有匹配项,请使用最新信息进行更新
- 如果小工具是新的或现有手册已过期,请使用 AFNetworking 下载小工具的用户手册(zip 文件)。手册被创建为一个与小工具有关系的单独实体(我已经这样做了,以防需要保存多个手册)。
应用程序第一次执行它时运行良好(即它必须创建所有新的小工具并为每个小工具下载手册)。如果我在服务器上更新小工具的手册并再次运行该应用程序,则会收到错误消息(我已在代码中标记了该行):
非法尝试在不同上下文中的对象之间建立关系“theGadget”
这些实体都是在同一个 MOC 上创建的,所以我不确定为什么会出现错误。无论如何,我从这里开始相信AFNetworking 的回调在主线程上,所以我可以使用一个 MOC。也许我犯了另一个错误,或者有更好的方法来做我想做的事情......?
-(void)populateCoreDataWithServerData {
// Fetch all the existing info from core data
theItems = [self loadFromDatabase:@"Gadgets" andSortDescriptor:nil];
int row = 0;
// Cycle through each entry in the parsed CSV data.
for (NSDictionary *itemDictionary in theItemsInCSV) {
// Check to see if we've downloaded this item previously.
Gadgets *gadget;
bool foundIt = FALSE;
bool needToUpdateZip = TRUE;
for (int i = 0; i < [theItems count]; ++i) {
// Check if we have downloaded it already. If so, update as the item in core data with any new data.
if ([[[theItems objectAtIndex:i] productCode] isEqualToString:[itemDictionary objectForKey:@"Product Code"]]) {
foundIt = TRUE;
gadget = [theItems objectAtIndex:i];
NSLog(@"Found this item in the local database. Won't be downloading it again.");
// Check if the zip file with the instruction manual needs updating.
if ([[[theItems objectAtIndex:i] zipURL] isEqualToString:[itemDictionary objectForKey:@"Manual Zip"]]) {
NSLog(@"The zip file is the same or non-existant, no need to update.");
needToUpdateZip = FALSE;
}
else {
NSLog(@"The zip file is different. Will download");
}
}
}
// If we haven't downloaded it before, create a new item. We'll update the fields in that.
if (foundIt == FALSE) {
gadget = (Gadgets *)[NSEntityDescription insertNewObjectForEntityForName:@"Gadget" inManagedObjectContext:self.managedObjectContext];
NSLog(@"Didn't find this item in the local database. Had better download it.");
}
// Update all the fields.
[gadget setName:[itemDictionary objectForKey:@"gadget name"]];
//Set some more attributes (product code etc)
// Download gadget manual (zip file) if it exists
if (needToUpdateZip == TRUE) { // Check if there's a URL in there
// Create a temp folder
if (![[NSFileManager defaultManager] fileExistsAtPath:[self tempDirectory]) { // Use Formidible Key as in identifier rather than the Product Code as the Form Key never has any spaces in it.
NSError* error;
if([[NSFileManager defaultManager] createDirectoryAtPath:[self tempDirectory] withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Directory created");
}
}
NSString *fileName = [[NSString alloc] initWithFormat:@"Temp%i.zip", row];
NSString *fileNameWithPath = [[self tempDirectory] stringByAppendingPathComponent:fileName];
// Download the zip
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[itemDictionary objectForKey:@"Manual Zip"]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:fileNameWithPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Successfully downloaded file to %@", [self tempDirectory]);
// Save the individual files to core data.
Manuals *manual = (ARData *)[NSEntityDescription insertNewObjectForEntityForName:@"Manuals" inManagedObjectContext:self.managedObjectContext];
[manual setTheGadget:gadget]; // ERROR APPEARS HERE **********************************
// Extract the zip file and set some attributes
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Download didn't work. Error: %@", error);
}
];
[operation start];
}
++row;
}
NSError *error;
if (![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error localizedDescription]);
}
}
提前致谢!!