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メソッドが 2 回目に呼び出されたときに発生します。編集 表示されている最初の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]];
    ...
    });
}

2 回目 (私の DeviceLinker クラスが私の checkInactiveLinks メソッドで非アクティブなリンクについてデータベースをチェックしようとしているときに時々クラッシュが発生するとき。このメソッドは での起動時に呼び出されますapplicationDidBecomeActive:

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

私が間違っている場合は修正してください。コードを読むと、persistentStoreCoordinator ゲッターが 2 回目に呼び出されたときに、__persistentStoreCoordinator が返され、新しいものを割り当てて初期化する必要はないと思います...

更新 2 if ステートメントのまったく同じ行で、これも時々取得します。

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

更新 3

ビルド スキームを編集し、[診断] タブでゾンビとログの例外を有効にしました。なるほど-[NSPersistentStoreCoordinator unlock]: message sent to deallocated instance 0x8916090。私のコードには明示的なロックがないことに注意してください。

4

4 に答える 4

19

同時に複数のスレッドからそのコードにアクセスしているようです。遅延インスタンス化を行うときは、「初回」の実行スレッドが 1 つだけ通過することを確認する必要があります。次の戦略を使用して、メイン スレッドでアクセスを同期できます。

- (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

私はスピン ロックを好みます。メイン スレッドで 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 に答える
1

スレッドを使用するために GCD を使用しています。

と:

次の行で完全に読み込まれる前に、アプリがクラッシュすることがあります。

並行性関連のバグの典型的な症状のように思えます。断続的で、一見間違った場所にあります。

CoreData には、非常に具体的な同時実行要件があります。あなたは彼らに会っていますか?

于 2012-04-30T19:30:48.427 に答える
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 に答える