保存使用AFNetworking下载的数据时,是否需要使用多个managedObjectContexts?

时间:2013-07-27 14:16:01

标签: multithreading core-data afnetworking

关于我正在做的事情的一些背景:

我从包含许多小工具数据的服务器下载CSV文件。然后使用CSV解析器将数据解析为NSDictionaries数组。完成后,下面的代码将字典中保存的信息写入核心数据。

快速解释下面代码的作用:

  • 获取所有现有核心数据项
  • 对于每个字典,检查产品代码是否与核心数据中已有的产品代码匹配
  • 如果没有匹配项,请创建一个新的小工具实体并保存其数据
  • 如果匹配,请使用最新信息
  • 进行更新
  • 如果小工具是新的或现有手册已过期,请使用AFNetworking下载小工具的用户手册(zip文件)。手册是作为一个单独的实体创建的,并且与小工具有关系(我已经完成了这个,以防需要保存多个手册)。

第一次应用程序执行此操作时,它工作正常(即必须为每个创建所有新小工具和下载手册)。如果我更新服务器上的小工具手册并再次运行应用程序,我会收到错误(我在代码中标记了该行):

  

非法尝试在不同上下文中的对象之间建立关系'theGadget'

实体都是在同一个MOC上创建的,所以我不确定为什么会出现错误。无论如何,我从here开始相信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]);
    }
}

提前致谢!!

1 个答案:

答案 0 :(得分:0)

更新现有数据时,我的解决方法是获取与小工具关联的现有手动实体并覆盖其数据,而不是删除手动实体并重新创建。

这不是一个真正的解决方案,所以如果你已经知道上面的代码有什么问题,请告诉我!