多线程核心数据和日志记录

时间:2013-02-25 09:17:25

标签: iphone ios objective-c core-data logging

背景信息

我差不多完成了我的应用。一切都很完美。然后客户端要求登录应用程序(即必须记录已完成的内容,回复内容等的各个点......)。

该应用程序允许用户创建保存在核心数据中的“消息”。然后将消息单独上载到服务器。消息在主线程上创建,并上载到后台线程的NSOperation子类中。

它与我之前使用的NSOperation子类的模板相同并且有效。我正在为多线程核心数据做所有最佳实践。

该应用程序的所有这一面都运行正常。

我添加了应用的日志记录部分。我创建了一个名为MyLogManager的单例和一个名为CoreData的{​​{1}}实体。该实体非常简单,只有LogEntrydate

代码

MyLogManager中的函数是......

text

反过来运行...

- (void)newLogWithText:(NSString*)text
{
    NSLog(@"Logging: %@", text);

    NSManagedObjectContext *context = [self context];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"LogEntry" inManagedObjectContext:context];

    LogEntry *logEntry = [[LogEntry alloc] initWithEntity:entity insertIntoManagedObjectContext:context];

    logEntry.text = text;
    logEntry.date = [NSDate date];

    [self saveContext:context];
}

- (NSManagedObjectContext*)context
{
    AppDelegate *appDelegate = (ThapAppDelegate*)[[UIApplication sharedApplication] delegate];

    NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    [managedObjectContext setPersistentStoreCoordinator:appDelegate.persistentStoreCoordinator];

    return managedObjectContext;
}

NSOperation主线程(其中很好的部分)......

- (void)saveContext:(NSManagedObjectContext*)context
{
    MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate];

    [[NSNotificationCenter defaultCenter] addObserver:appDelegate
                                             selector:@selector(mergeChanges:)
                                                 name:NSManagedObjectContextDidSaveNotification
                                               object:context];

    NSError *error = nil;
    if ([context hasChanges] && ![context save:&error]) {
        NSLog(@"Unhandled error %@, %@", error, [error userInfo]);
        abort();
    }

    [[NSNotificationCenter defaultCenter] removeObserver:appDelegate name:NSManagedObjectContextDidSaveNotification object:context];
}

问题

我上传消息的- (void)main { //create context and retrieve NSManagedObject using the NSManagedObjectID passed in as a parameter to operation self.message.lastSendAttempt = [NSDate date]; [self startUpload]; [self completeOperation]; //This doesn't get run because the startUpload method never returns } - (void)startUpload { [[MyLogManager sharedInstance] logSendingMessageWithURLParameters:[self.event URLParameters]]; //this is a convenience method. It just appends some extra info on the string and runs newLogWithText. //Do some uploading stuff here... //The operation stops before actually doing the upload when logging to CoreData. } 子类(在后台线程上)调用此NSOperation函数,但它也会更新正在上传的消息。 newLogWithText使用相同的方法来获取和保存核心数据上下文。 (即它会更新上次发送的日期,如果发送成功也会更新。)

这是我第一次尝试处理同步写入并保存到核心数据。

我没有收到任何错误,应用程序继续“正常工作”。但操作永远不会完成。我试图用断点调试它,但是当我使用断点时它可以正常工作。没有断点,操作永远不会完成,上传永远不会发生。然后它只是坐在那里阻止它所在的队列,并且不能发送其他消息。

在我的NSOperation中(我知道这不是理想的地方,但它是新项目的默认设置而我没有改变它)appDelegate方法只是......

mergeChanges

我已经尝试将'newLogWithText'函数抛弃到另一个线程,甚至没有运气的主线程。

我现在正准备尝试,但将合并的“waitUntilDone”更改为YES。 (刚注意到这一点)。 (这没用)。

我90%肯定这是由于同时写入不同的上下文和解决冲突,因为这是我第一次处理这个问题。如果我注释掉- (void)mergeChanges:(NSNotification *)notification { [self.managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:NO]; } 函数,那么一切正常。

目前唯一的选择是从核心数据中删除newLogWithText并将日志保存到LogEntry内的数组中,但感觉不对。还有另一种方式吗?

修改

我现在已经更改了它,因此用户NSUserDefaults并且它可以正常运行。它只是一个hacky解决方案。

0 个答案:

没有答案