Сбой при добавлении постоянного хранилища (iCloud enabled) в делегат приложения

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

Самое новое обновление

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

Еще одно дополнение для правильной настройки

  • Я обнаружил, что после обновления приложения, данные которого связаны с iCloud с учетной записью, может привести к сбою при его открытии, потому что данные iCloud данные попытаются сразу же слиться на устройство (где устройство еще не настроило свое постоянное хранилище). Теперь я добавил. @property (nonatomic, readwrite) BOOL unlocked; в AppDelegate.h и @synthesize unlocked; на AppDelegate.m. Затем я изменил -. (NSPersistentStoreCoordinator *)persistentStoreCoordinator метод, а также а также метод - (void)mergeChangesFrom_iCloud, оба из которых будут показаны ниже (в середине для настройки постоянного хранилища и в нижней части для метода слияния с iCloud). По сути, я говорю приложению запретить iCloud объединять данные до тех пор, пока приложение не настроит свое постоянное хранилище. В противном случае произойдет сбой приложения из-за нечитаемых ошибок.

Вот как я настраиваю свой persistentStoreCoordinator:

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


    // here is where you declare the persistent store is not prepared;
    self.unlocked = NO;

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

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];   

    NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSDictionary *options = nil;

        NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:nil];

        NSString *coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:@"data"];

        if (coreDataCloudContent.length != 0) {
            // iCloud enabled;

            cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
            options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, @"<bundleIdentifier>.store", NSPersistentStoreUbiquitousContentNameKey, cloudURL, NSPersistentStoreUbiquitousContentURLKey, nil];

        } else {

            // iCloud not enabled;
            options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

        }

        NSError *error = nil;

        [psc lock];

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

            NSLog(@"bad things %@ %@", error, [error userInfo]);
            abort();

        }
        [psc unlock];

        // the store is now prepared and ready for iCloud to import data;
        self.unlocked = YES;


        dispatch_async(dispatch_get_main_queue(), ^{

            NSLog(@"iCloud persistent store added");

            [[NSNotificationCenter defaultCenter] postNotificationName:@"RefetchAllDatabaseData" object:self userInfo:nil];

        });
    });

    return __persistentStoreCoordinator;
}

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

Я знаю, что некоторые люди все еще испытывают трудности с этим и могут использовать этот вопрос в качестве справочника по настройке своих собственных приложений Core Data с поддержкой iCloud, поэтому я хочу обновлять эту статью каждый раз, когда вношу изменения в свой личный код, чтобы все вы могли использовать код, который работает у меня. В этом обновлении я изменил начальный cloudURL с [fileManager URLForUbiquityContainerIdentifier:@"."] на [fileManager URLForUbiquityContainerIdentifier:nil], обеспечив сбор информации о контейнере из файла прав доступа.

Дополнительные методы _notificationArray определяется следующим образом: @property (nonatomice, strong) NSMutableArray *notificationArray; @synthesize notificationArray = _notificationArray;

- (void)mergeChangesFrom_iCloud:(NSNotification *)notification {
    if (self.unlocked) {
        NSManagedObjectContext *moc = [self managedObjectContext];

        if (self.notificationArray.count != 0) {
            for (NSNotification *note in _notificationArray) {
                [moc performBlock:^{
                    [self mergeiCloudChanges:note forContext:moc];
                }];
            }
            [_notificationArray removeAllObjects];
            [moc performBlock:^{
                [self mergeiCloudChanges:notification forContext:moc];
            }];
        } else {
            [moc performBlock:^{
                [self mergeiCloudChanges:notification forContext:moc];
            }];
        }
    } else {
        if (_notificationArray == nil) {
            _notificationArray = [[NSMutableArray alloc] init];
        }
        [_notificationArray addObject:notification];
    }
}

- (void)resetStore {
    [self saveContext];
    __persistentStoreCoordinator = nil;
    __managedObjectContext = nil;
    // reset the managedObjectContext for your program as you would in application:didFinishLaunchingWithOptions:
    myMainView.managedObjectContext = [self managedObjectContext];
    // the example above will rebuild the MOC and PSC for you with the new parameters in mind;
}

Далее есть метод mergeiCloudChanges:forContext::

- (void)mergeiCloudChanges:(NSNotification *)note forContext:(NSManagedObjectContext *)moc {
    // below are a few logs you can run to see what is being done and when;
    NSLog(@"insert %@", [[note userInfo] valueForKey:@"inserted"]);
    NSLog(@"delete %@", [[note userInfo] valueForKey:@"deleted"]);
    NSLog(@"update %@", [[note userInfo] valueForKey:@"updated"]);
    [moc mergeChangesFromContextDidSaveNotification:note];

    NSNotification *refreshNotification = [NSNotification notificationWithName:@"RefreshAllViews" object:self userInfo:[note userInfo]];
    [[NSNotificationCenter defaultCenter] postNotification:refreshNotification];
    // do any additional work here;
}

Начальная проблема

  • Используя iCloud на iOS 5.0.1, я периодически получаю ошибки, относящиеся к с постоянным хранилищем. Я собираюсь продолжать обновлять эту статью новой информацией по мере того, как я буду находить ее в ходе экспериментов, но пока что решение, которое я предложил, является единственным способом заставить приложение работать (к сожалению, решение jlstrecker'а не сработало для меня), как только я начинаю видеть ошибку. как только я начинаю видеть ошибку, которая выглядит следующим образом:

    -NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:: CoreData: Ubiquity: Ошибка при попытке чтения корневого url ubiquity: file://localhost/private/var/mobile/Library/Mobile%20Documents/./data/. Ошибка: Error Domain=LibrarianErrorDomain Code=1 "Операция не может быть завершена. (Ошибка 1 LibrarianErrorDomain - Невозможно Unable to initiate item download.)". UserInfo=0x176000 {NSURL=file://localhost/private/var/mobile/Library/Mobile%20Documents/./data/, NSDescription=Невозможно инициировать загрузку элемента.}

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

    Приложение падает здесь:

    if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
    
     NSLog(@"bad things %@ %@", error, [error userInfo]);
     abort();
    
    }
    

    Лог никогда не попадает в лог, как и abort. Я просто вижу вышеуказанную ошибку и само приложение становится невосприимчивым. Если кто-то может помочь мне в правильном направлении, я буду очень признателен.

Предыдущие проблемы/вопросы

  • Похоже, это продолжается даже после обновления с бета-версии до публичного релиза 5.0.1. В последний раз это случилось со мной после изменения моей модели данных управляемого контекста. Учитывая, что я еще не я еще не выпустил приложение, я не стал беспокоиться о слиянии новой версии модели. Я просто удалил и переустановил приложение на своих устройствах, но затем оно отказалось работать с данными, хранящимися в контейнере iCloud контейнере, под этим я подразумеваю, что я получил ошибку о том, что магазин не может загрузить элементы. Я предполагаю, что это связано с конфликтующими типов моделей, что вполне логично. Так что, похоже, вам просто нужно избавиться от данных внутри контейнера iCloud, не избавляясь от от контейнера. Удаление данных iCloud, похоже, уничтожает все. по сути, отключая контейнер и App ID. Поскольку это казалось проще, я попробовал создать новый контейнер, как предложил jlstrecker, но, к сожалению, это не помогло. Поэтому мне снова пришлось проделать шаги, описанные в моем ответе, что снова помогло. трюк. Но учитывая, как раздражает необходимость создавать новые App ID и обновлять профили инициализации каждый раз, я подумал, что лучше всего будет обновить то, что я узнал, чтобы потенциально сузить причину и получить к более быстрому решению.

    Переход через iCloud > Хранилище и резервное копирование > Управление хранилищем, а затем удаление приложения кажется лучшим решением для удаления данных. данные, но это, похоже, повреждает контейнер, что приводит к появлению вышеуказанной ошибке. И после успешного выполнения этого действия, независимо от того, сколько раз раз я удаляю приложение и заново устанавливаю его на устройство (чтобы как будто оно впервые появилось на устройстве и, надеюсь. воссоздать контейнер), я никогда не могу добиться того, чтобы приложение отображалось в списке Документы и данные. Это несколько беспокоит, если это означает. что любой, кто удаляет данные из своего iCloud подобным образом, означает, что iCloud больше никогда не будет работать для приложения. Я использую только профиль разработки приложения, так что, возможно, использование профиль распространения может иметь какое-то значение, но мне нужно будет проверить это, прежде чем говорить что-то определенное.

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

38
задан justin 18 October 2012 в 22:55
поделиться