7

我的应用程序有时会在以下行完全加载之前崩溃:

if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])

这个 if 状态所在的完整方法如下所示(我认为这是非常标准的):

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil) {
        return __persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}

更新

崩溃发生在第二次-(NSPersistentStoreCoordinator *)persistentStoreCoordinator调用该方法时。编辑 从第一个可见的 viewController 调用它的第一次时间:

- (void)updateStats {
    NSLog(@"Updating stats");
    dispatch_queue_t request_queue = dispatch_queue_create("updateNumberOfSchedules", NULL);
    dispatch_async(request_queue, ^{
         AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
    ...
    });
}

第二次(当我的 DeviceLinker 类将在我的 checkInactiveLinks 方法中检查数据库中的非活动链接时,有时会发生崩溃。此方法在启动时调用applicationDidBecomeActive

-(void) checkInactiveLinks {
    AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
    [newMoc setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
    ...
}

如果我错了,请纠正我,但阅读我的代码我会认为第二次调用 persistentStoreCoordinator getter 时它应该返回 __persistentStoreCoordinator 而不是分配和初始化一个新的......

更新 2 在 if 语句的同一行,我也时不时得到这个:

-[__NSCFDictionary _hasPrecomputedKeyOrder]: unrecognized selector sent to instance 0x7dd3770

更新 3

我编辑了我的构建方案并在诊断选项卡下打开了僵尸和日志异常。现在我明白了-[NSPersistentStoreCoordinator unlock]: message sent to deallocated instance 0x8916090。请注意,我的代码中没有任何显式锁定。

4

4 回答 4

19

看起来您正在同时从多个线程进入那段代码。当您进行延迟实例化时,您必须确保仅通过一个执行线程的“第一次”将同时通过。您可以使用以下策略在主线程上同步访问它。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil) {
        return __persistentStoreCoordinator;
    }

    // Add this block of code.  Basically, it forces all threads that reach this
    // code to be processed in an ordered manner on the main thread.  The first
    // one will initialize the data, and the rest will just return with that
    // data.  However, it ensures the creation is not attempted multiple times.
    if (![NSThread currentThread].isMainThread) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            (void)[self persistentStoreCoordinator];
        });
        return __persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}
于 2012-05-02T19:39:41.037 回答
1

我正在使用 GCD 来使用线程。

和:

我的应用程序有时会在以下行完全加载之前崩溃:

听起来像是并发相关错误的典型症状;断断续续,似乎在错误的位置。

CoreData 有非常具体的并发要求。你会见他们吗?

于 2012-04-30T19:30:48.427 回答
1

我更喜欢自旋锁,它比在主线程中递归调用 getter 方法更清晰。这是我的解决方案:

#import <libkern/OSAtomic.h>

@implementation MyClass {
    OSSpinLock _lock;
}

- (instancetype)init {
    self = [super init];
    if (self){
        _lock = OS_SPINLOCK_INIT;
    }
}


 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil) {
        return __persistentStoreCoordinator;
    }

    // Lock the current thread
    OSSpinLockLock(&_lock);

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    } 

    // Unlock
    OSSpinLockUnlock(&_lock);

    return __persistentStoreCoordinator;
}
于 2016-03-16T21:48:43.020 回答
0

我认为当你添加一个新的持久存储时,你应该首先锁定持久存储协调器,这样它就不会干扰其他持久存储。

在下面的代码中psc是对新创建的持久存储协调器的单独引用。如果我正确理解您的目的,则可能应该dispatch_async编辑该方法的这一部分。

[psc lock];
if (![__persistentStoreCoordinator 
   addPersistentStoreWithType:NSSQLiteStoreType 
                configuration:nil 
                          URL:storeURL 
                       options:nil error:&error]) {
   // deal with the error
}
[psc unlock];
于 2012-04-30T19:38:20.043 回答