【问题标题】:Core Data doesn't save data until the app is closed在应用关闭之前,Core Data 不会保存数据
【发布时间】:2014-01-11 04:06:39
【问题描述】:

我正在尝试在完成网络请求后将数据保存到核心数据中。 在AppDelegate 我有我的背景。下面是获取上下文的代码:

- (NSManagedObjectContext *)contex {
    @synchronized(self) {
        if (_contex == nil) {
            _contex = [[NSManagedObjectContext alloc] init];
            [_contex setPersistentStoreCoordinator:self.persistentStoreCoordinator];
        }
        return _contex;
    }
}

就像 Apple 指南所说的那样,我有一个与多个上下文共享的持久存储坐标。

这是我从网络获取数据、获取上下文并调用将新值保存到核心数据中的方法的代码。

NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *localFile, NSURLResponse *response, NSError *error) {
            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
            UIImage *image;
            if (!error) {
                NSData *imageData = [NSData dataWithContentsOfURL:localFile];
                image = [UIImage imageWithData:imageData];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"thumbnailIsSetted" object:self userInfo:@{@"image": image,
                                                                                                                           @"PhotoUrl": photo.url}];
                    @synchronized(self) {
                        NSManagedObjectContext *context = [(SocialMapAppDelegate *)[[UIApplication sharedApplication] delegate] contex];
                        [Photo addThumbnailData:imageData toPicture:photo.url fromContext:context];
                    }
                });
            } else {
                //if we get an error, we send the default icon
                image = [UIImage imageNamed:@"Photo-thumbnail"];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"thumbnailIsSetted" object:self userInfo:@{@"cached image": image,
                                                                                                                           @"PhotoUrl": photo.url}];
                });
            }
        }];
        [task resume]; //we resume the task in case it is souspended
    }];

这是我用来将数据保存到核心数据中的方法:

+ (void)addThumbnailData:(NSData *)data toPicture:(NSString *)pictureUrl fromContext:(NSManagedObjectContext *)context 
{
    if (pictureUrl && context) {
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
        request.predicate = [NSPredicate predicateWithFormat:@"url == %@",pictureUrl];
        NSError *error = nil;
        NSArray *matches = [context executeFetchRequest:request error:&error];
        if ([matches count] == 1) {
            Photo *photo = [matches lastObject];
            photo.thumbnailData = data;

            if (![context save:&error]) {
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            }
        }
    }
}

我不知道问题出在哪里,上下文不是零,而且我没有收到任何错误。如果我重新启动应用程序,数据就在那里。

【问题讨论】:

  • [matches count] 返回什么值?
  • 您希望在 UI 中的何处刷新数据?

标签: ios objective-c core-data nsmanagedobjectcontext


【解决方案1】:

除非您在应用程序中使用多线程设计,否则我不建议您使用多个上下文。我建议将应用程序剥离到一个上下文中,以避免传递通知。 99% 的时间根本不需要它。

此外,如果您使用父/子上下文,我不建议重新使用子上下文。它们应该是暂时的;用于单个任务,然后丢弃。这样做的原因是数据更改仅以一种方式流动。向上。如果你改变一个孩子的某些东西,它不会被推到任何兄弟姐妹身上。此外,子上下文变得陈旧。如果您在主上下文中进行更改,所有子级都将过时。

您的 UI 应该在整个应用程序中使用单个 NSManagedObjectContext。这很可能会解决您的问题。

【讨论】:

  • 但我在这个线程中读到,link 在整个应用程序中只有一个 NSManagedObjectContext 是一种不好的做法。
  • 我解决了这个问题,非常感谢您的宝贵时间!
  • 那个链接说的很不一样。它不鼓励 vcs 自己获取上下文。它们应该被传递一个上下文 => 增加可重用性
  • 拥有单一上下文和使用单例之间存在巨大的区别。使用 Singleton 是不好的,因为你不能轻易地销毁它或重置它。推荐使用单个NSManagedObjectContext 作为UI 的方法。
【解决方案2】:

代码看起来不错...保存会将上下文的内容保存到磁盘上。要刷新其他上下文,您必须收听 ContextDidSave 通知并合并数据

先观察:

...
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(mergeChanges:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:managedObjectContext];            
...

然后合并

- (void)mergeChanges:(NSNotification *)notification {
    // Merge changes into the main context on the main thread
    [self.mainManagedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
    withObject:notification
 waitUntilDone:YES];
}

【讨论】:

  • 您在正确的上下文中调用 mergeChangesFromContextDidSaveNotification 吗?它没有合并吗? .. 当然你也必须在合并完成后刷新你的 UI
  • 是的,上下文是正确的,并且执行了合并,但是当我更新视图,并再次向核心数据发送请求时,这没有任何效果,并且再次下载数据来自互联网
  • 我解决了这个问题,非常感谢您的宝贵时间!
【解决方案3】:

我解决了,问题出在我可视化并请求数据的类上,而不是通过这种方式从 appDelegate 获取上下文:

[(SocialMapAppDelegate *)[[UIApplication sharedApplication] delegate] contex];

我这样做了

[[SocialMapAppDelegate alloc] init].contex

通过这种方式,我简单地创建了另一个上下文和另一个商店,这是完全错误的,所以我只需将上面的代码替换为

    [(SocialMapAppDelegate *)[[UIApplication sharedApplication] delegate] contex];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2019-11-19
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    相关资源
    最近更新 更多