2015-10-21 4 views
4

Моего приложения В последнее время получает эти сбои из crashlytics, что происходит только на iOS9Краша на iOS9 с - [NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]

Fatal Exception: NSInternalInconsistencyException
Это NSPersistentStoreCoordinator не имеет постоянных магазинов (файл поврежден). Он не может выполнить операцию сохранения.

Последний вызов из отчета

-[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:] 

и это, как NSPersistentStoreCoordinator создается

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

    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate; 

    NSURL *storeURL = [[delegate applicationDocumentsDirectory] URLByAppendingPathComponent:@"database.sqlite"]; 

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; 

    NSError* error = nil; 

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
                configuration:nil 
                  URL:storeURL 
                 options:@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} error:&error]) 
    { 
     NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo); 
     return nil; 
    } 

    return _persistentStoreCoordinator; 
} 

Кто-нибудь знает, что может быть причиной этих аварий?

ответ

3

Я не испытал эту ошибку на iOS9. Однако вы должны посмотреть свои журналы, чтобы узнать, какие у вас ошибки. Возможно ли, что вы столкнулись со своей «Ошибка добавления постоянного хранилища» при создании PSC?

У вашего метода возникла проблема в том, что если вы когда-нибудь столкнетесь с этой ошибкой, последующие вызовы возвратят PSC, который не будет ни нул, ни правильно настроен.

Причина в том, что вы назначили свой _persistentStoreCoordinator, прежде чем он будет успешно настроен. Таким образом, если есть какая-либо ошибка, вы возвращаете нуль, но при следующем вызове этого метода вы вернете PSC без магазинов.

В любом случае вы должны изменить этот метод, чтобы вы только возвращали либо ноль, либо полностью работоспособный PSC.

Я бы изменил этот метод на что-то подобное. Примечание, однако, что я никогда бы не построил такой базовый стек данных, как этот. Однако, по крайней мере, следующий код исправит вашу ошибку, если вы можете вернуть частично созданный PSC.

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

    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate; 
    NSURL *storeURL = [[delegate applicationDocumentsDirectory] 
     URLByAppendingPathComponent:@"database.sqlite"]; 

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] 
     initWithManagedObjectModel:self.managedObjectModel]; 
    NSError *error = nil; 
    if (![psc addPersistentStoreWithType:NSSQLiteStoreType 
          configuration:nil 
            URL:storeURL 
           options:@{NSMigratePersistentStoresAutomaticallyOption:@YES, 
              NSInferMappingModelAutomaticallyOption:@YES} 
            error:&error]) { 
     NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo); 
    } else { 
     _persistentStoreCoordinator = psc; 
    } 

    return _persistentStoreCoordinator; 
} 

EDIT

Не хватает места в комментариях, чтобы ответить на ваш вопрос, так что я положил его здесь.

@JodyHagins - также, вы говорите, что вы не будете строить свой стек, как это, вы можете, дайте мне знать, что случилось с моим стеком? - AWillian

Я сделал это замечание, потому что код размещен устрашающе похож на шаблон ядра данных в Xcode по умолчанию. Вы вызываете приложение-делегат для получения каталога, указывая, что это не в приложении-делетете, что хорошо.

Однако этот метод указывает на то, что вы обращаетесь к нему с ленивым «где угодно», что указывает на то, что ваш стек не построен так, как я бы создал стек (тем более, что вы также включаете параметры миграции).

Я не хотел подразумевать, что то, что вы делали, было неправильным, само по себе, это не то, как я это сделаю.

Теперь я буду первым, чтобы сказать, что то, что я делаю, это то, что я делаю ... и я не говорю, что это правильный путь ... только по-моему. На самом деле, я не видел, чтобы кто-то другой действительно делал то, что я делаю (я действительно подклассифицировал NSManagedObjectContext, хотя я не помню предупреждения и держался подальше от пронзительных бит). Это само по себе может указывать на то, что то, что я делаю, может быть неправильным для вас или кого-либо еще. Но я нашел, что это правильно для меня, и довольно сложные приложения, которые мне пришлось реализовать.

Итак, как мне построить стек?

Ну, это достойно чего-то гораздо более глубокого, чем ответ SO, поэтому я буду краток. Это также зависит от типа стека - родителя/ребенка, братьев и сестер с тем же PSC, двоюродных братьев с разными PSC, но в тех же магазинах.

Во-первых, я не предоставляю отдельный доступ к модели и координатору. Вы можете легко получить доступ к ним из контекста, и обычно это приводит к большим проблемам, чем их ценность.

Вне испытаний и тривиальных примеров, я всегда создаю мой MOC асинхронно, что-то вроде этого ...

+ (void)createWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType 
         completion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion; 

MOM для создания и назначен ККП, ККП создается и присваивается MOC , Это происходит асинхронно, так что потенциально длительный процесс открытия и инициализации может выполняться в фоновом потоке. Обработчик завершения вызывается в пределах performBlock, поэтому MOC можно использовать чисто. Это также предотвращает использование до того, как MOC будет полностью настроен и прочитан.

Даже если вызывается с использованием типа параллелизма основной очереди, вся работа выполняется в фоновом потоке, так что в основной поток вызывается только завершение.

Я также использую тот же шаблон при создании связанных MOC для импорта и временных целей.

+1

Я бы честно добавил 'abort()' после 'NSLog', чтобы убедиться, что проблема поймана как 99.999% времени, когда приложение бесполезно, если исходный код не инициализирован правильно. –

+0

@ MarcusS.Zarra - Согласовано. –

+0

Спасибо, что поймали это, похоже, что это наиболее вероятная причина. Хотя интересно, что это началось только на iOS9, и меня также интересует, что означает [NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]. – AWillian

2

Ответ от форума Apple dev here, который также объясняет возможную причину и решение.

Причина в дескрипторе: ваше приложение попыталось открыть открытое хранилище, когда устройство было заблокировано, и ваш код сработал над API защиты данных.

Это то, что вы путешествуете на новых устройствах и новых версиях iOS, потому что новое устройство достаточно быстро, чтобы ваше приложение работало до того, как код защиты данных будет выполнен с переходом.

Решение такого рода вопрос может быть что-то вроде ниже

Вы в значительной степени должны идти в свой старт до кода, и переписать его так, что он проверяет, есть ли защищенные данные доступны, а затем задерживает запуск ваших основных данных до тех пор, пока не будет применено приложениеProtectedDataDidBecomeAvailable.

Смежные вопросы