2013-09-24 4 views
1

Я работаю над облегченной оболочкой для UIManagedDocument, которая управляет наличием нескольких документов в учетной записи iCloud человека. См.: APManagedDocumentПравильное использование резервных хранилищ iCloud

Я полагаюсь на использование резервных хранилищ в iOS 7 и заботясь как можно меньше о текущем состоянии iCloud. Таким образом, выпускающие основные данные делать то, что он делает лучше всего в отношении замещающих магазинов основаны на моем понимании от WWDC 2013 Видео - Session 207 What’s New in Core Data and iCloud

Сначала краткий обзор того, как работает мой менеджер: Я создаю все мои UIManagedDocuments в местном песочнице и установите соответствующие параметры хранилища, чтобы включить синхронизацию iCloud. Я никогда не перемещаю пакет UIManagedDocument из песочницы.

  • Когда я хочу знать, какие документы существуют в облаке, я выполняю запрос метаданных.
  • Когда я хочу открыть один из этих документов, я проверяю, существует ли он в локальной песочнице, и если он не создается в локальной изолированной программной среде. (Это требует, чтобы приложение должно было ждать уведомления, соответствующего сообщению Using local storage: 0.)
  • С этим настройкой мне никогда не нужно знать, включен ли iCloud или вошел в систему. Я просто работаю локально и позволяю основным данным с iCloud.

До сих пор все работает замечательно, но я столкнулся с небольшим количеством маринада со сценарием, когда пользователь создает новый документ до входа в ICloud и я представлены следующие вопросы:

  • I не может выполнить запрос метаданных, потому что iCloud не запрашивает запрос.
  • Из-за 1 я должен вернуться к выполнению интеллектуального локального сканирования, ищущего пакеты, на которых есть «local/store/persistentStore», и перечисляя их как действительные документы.
  • Позже, когда пользователь входил в систему, я понял, что данные ядра будут перемещать данные локального хранилища в облако, но я этого не вижу. Вместо этого я вижу, что для учетной записи iCloud создается новый постоянный магазин и нет данных.

Мой большой вопрос - это правильный подход, когда дело доходит до местного резервного магазина? Где мои предположения ошибочны?

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

У меня есть дубликат этого вопроса на форумах разработчиков Apple. Я обновлю эту тему с любыми выводами, которые я получаю оттуда. Я думаю, что этот вопрос важен и остается нерешенным с выпуском iOS 7. Резервные магазины - это огромный прогресс в технологии iCloud, но часть локального хранилища все еще немного неопределена.

+0

я открыл тикет с Apple, мы надеемся решить этот вопрос. – dtrotzjr

+0

@dtrotzr .... любое обновление по билету поддержки? У меня также такая же проблема .... – Max

+0

@Max см. Мой ответ ниже. Apple, наконец, вернулась ко мне, но меня не волнует ответ, который я чувствую, что инженер не нашел времени, чтобы полностью понять мой ответ, или я делаю все неправильно с резервными магазинами. – dtrotzjr

ответ

2

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

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

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

Наконец, после завершения миграции я запускаю новое сканирование документов.

Это работает, но это немного взломать.

Обратитесь к APManagedDocument фиксации: 421aaae

+0

Да, если iCloud переключается с недоступного на доступный, достаточно ли повторно открыть документ с параметрами, чтобы они перенесли их в облако, но что вы делаете в противоположном сценарии, где у пользователя есть документы в облаке, и он переключает iCloud из ON в положение OFF в настройках? Как изменить документ из iCloud только на локальный? Достаточно ли закрыть и открыть его без параметров iCloud? –

+0

В этом случае у вас даже нет доступа к этому документу. Вы очищаете свое состояние и двигаетесь дальше. – dtrotzjr

+0

Извините, я имел в виду, что пользователь устанавливает iCloud в «приложение настроек/документы и данные», но в «комплекте настроек приложений», как он может сделать в iWork. Устройство все еще имеет доступ iCloud, и если пользователь хочет сохранить данные на устройстве, я должен переместить UIManagedDocument из облака только на локальный. –

2

я, наконец, получил ответ сегодня. Я не на 100% уверен, что он понял мой вопрос, но я собираюсь потратить некоторое время на понимание его ответа, прежде чем я вынес решение.

Вот его ответ:

Благодарим Вас за запрос к компании Apple Worldwide Developer Technical Support . Я отвечаю, чтобы сообщить вам, что я получил ваш запрос на техническую помощь .

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

Вы могли бы реализовать этот метод класса к вашему UIManagedDocument подкласса:

  • (аннулируются) moveDocumentAtURL: (NSURL *) sourceDocumentURL toUbiquityContainer: (NSURL *) ubiquityContainerURL;

Этот метод будет по существу создать новый документ в «ubiquityContainerURL», и перенести магазин из «sourceDocumentURL» до «ubiquityContainerURL». Для выполнения миграции вы должны использовать «migratePersistentStore».

Вот пример:

// The name of the file that contains the store identifier. 
static NSString *DocumentMetadataFileName = @"DocumentMetadata.plist"; 

// The name of the file package subdirectory that contains the Core Data store when local. 
static NSString *StoreDirectoryComponentLocal = @"StoreContent"; 

// The name of the file package subdirectory that contains the Core Data store when in the cloud. The Core Data store itself should not be synced directly, so it is placed in a .nosync directory. 
static NSString *StoreDirectoryComponentCloud = @"StoreContent.nosync"; 

+ (NSDictionary *)optionsForStoreAtURL:(NSURL *)url { 

    NSURL *metadataDictionaryURL = [url URLByAppendingPathComponent:DocumentMetadataFileName]; 
    NSDictionary __block *storeMetadata = nil; 

    /* 
    Perform a coordinated read of the store metadata file; the coordinated read ensures it is downloaded in the event that the document is cloud-based. 
    */ 
    NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil]; 
    [fileCoordinator coordinateReadingItemAtURL:metadataDictionaryURL options:0 error:NULL byAccessor:^(NSURL *newURL) { 
     storeMetadata = [[NSDictionary alloc] initWithContentsOfURL:newURL]; 
    }]; 

    NSString *persistentStoreUbiquitousContentName = nil; 

    if (storeMetadata != nil) { 

     persistentStoreUbiquitousContentName = [storeMetadata objectForKey:PersistentStoreUbiquitousContentNameKey]; 
     if (persistentStoreUbiquitousContentName == nil) { 
      // Should not get here. 
      NSLog(@"ERROR in optionsForStoreAtURL:"); 
      NSLog(@"persistentStoreUbiquitousContentName == nil"); 
      abort(); 
     } 
    } 
    else { 

     CFUUIDRef uuid = CFUUIDCreate(NULL); 
     CFStringRef uuidString = CFUUIDCreateString(NULL, uuid); 
     persistentStoreUbiquitousContentName = (__bridge_transfer NSString *)uuidString; 
     CFRelease(uuid); 
    } 

    // NSPersistentStoreUbiquitousContentURLKey should be the TransactionLogs directory. 

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          persistentStoreUbiquitousContentName, NSPersistentStoreUbiquitousContentNameKey, 
          [[self URLForUbiquityTransactionLogs] URLByAppendingPathComponent:persistentStoreUbiquitousContentName] , NSPersistentStoreUbiquitousContentURLKey, nil]; 

    return options; 
} 

+ (void)moveDocumentAtURL:(NSURL *)sourceDocumentURL toUbiquityContainer:(NSURL *)ubiquityContainerURL { 

    if (ubiquityContainerURL == nil) { 

     // iCloud isn't configured. 
     NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 
           NSLocalizedString(@"iCloud does not appear to be configured.", @""), NSLocalizedFailureReasonErrorKey, nil]; 
     NSError *error = [NSError errorWithDomain:@"Application" code:404 userInfo:dict]; 
     NSLog(@"%@", [error localizedFailureReason]); 
     return; 
    } 

    // Move the document to the cloud using its existing filename 
    NSManagedObjectModel *model = [self managedObjectModel]; 
    NSDictionary *ubiquitousOptions = [self optionsForStoreAtURL:sourceDocumentURL]; 

    NSString *documentName = [[sourceDocumentURL lastPathComponent] stringByDeletingPathExtension]; 
    documentName = [documentName stringByAppendingPathExtension:@"wwWhat"]; 
    NSURL *destinationURL = [ubiquityContainerURL URLByAppendingPathComponent:documentName]; 

    dispatch_queue_t q_default; 
    q_default = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

    dispatch_async(q_default, ^{ 

     NSError __block *error = nil; 

     NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init]; 
     [coordinator coordinateWritingItemAtURL:destinationURL options:NSFileCoordinatorWritingForReplacing error:nil byAccessor:^(NSURL *destination) { 

      NSFileManager *fileManager = [[NSFileManager alloc] init]; 
      [fileManager removeItemAtURL:destination error:nil]; 

      NSURL *destinationStoreDirectoryURL = [destination URLByAppendingPathComponent:StoreDirectoryComponentCloud isDirectory:YES]; 
      NSURL *destinationStoreURL = [destinationStoreDirectoryURL URLByAppendingPathComponent:StoreFileName isDirectory:NO]; 

      NSURL *sourceStoreURL = [[sourceDocumentURL URLByAppendingPathComponent:StoreDirectoryComponentLocal isDirectory:YES] URLByAppendingPathComponent:StoreFileName isDirectory:NO]; 
      NSURL *originalMetadataURL = [sourceDocumentURL URLByAppendingPathComponent:DocumentMetadataFileName isDirectory:NO]; 
      NSURL *destinationMetadataURL = [destination URLByAppendingPathComponent:DocumentMetadataFileName isDirectory:NO]; 

      [fileManager createDirectoryAtURL:destinationStoreDirectoryURL withIntermediateDirectories:YES attributes:nil error:nil]; 
      [fileManager copyItemAtURL:originalMetadataURL toURL:destinationMetadataURL error:nil]; 

      NSPersistentStoreCoordinator *pscForSave = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: model]; 
      id store = [pscForSave addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sourceStoreURL options:nil error:nil]; 

      id success = [pscForSave migratePersistentStore:store toURL:destinationStoreURL options:ubiquitousOptions withType:NSSQLiteStoreType error:&error]; 

      if (success) { 
       [fileManager removeItemAtURL:sourceDocumentURL error:NULL]; 
      } 
      else { 
       NSLog(@"Failed to migrate store: %@", error); 
      } 
     }]; 
    }); 
} 
1

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

Один хороший рабочий пример из них все, что я спросить ...

Любая идея, как можно было бы получить доступ к этим файлам из OSX?

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

EDIT: Я просто поближе рассмотрел ваш APManagedDocumentManager, и вы, похоже, не включаете путь iCloud в значение NSPersistentStoreUbiquitousContentURLKey. Если я не пропустил что-то, вы просто используете подкаталог не полный путь iCloud, также вы используете NSString, а не URL (не уверен, что это имеет значение).

РЕДАКТИРОВАТЬ: Возможно, у нас должна быть дискуссия по телефону? Во всяком случае, некоторые из моих результатов ниже: Я только что установил Mavericks и после того, как дважды просмотрел видео, тестируя следующее: Создайте новые файлы, используя только код ниже - без UIManagedDocument или что-нибудь еще. _storeURL указывает на локальный каталог, как указано в видео. И я не использую NSPersistentStoreUbiquitousContentURLKey, потому что это больше не нужно. На данный момент у моего имени нет UUID.

Когда я делаю это на любом устройстве, тогда каталог CoreData создается вне каталога документов iCloud. Внутри каталога CoreData находятся подкаталоги для каждого из имен файлов, и внутри них находятся различные zip-файлы и вещи, которые предположительно являются базовыми и лог-файлами. Никаких признаков DocumentMetaData.plist. Таким образом, это выглядит довольно многообещающе, но я не могу понять, как можно «открыть» новые файлы, которые появляются. Я надеюсь, что мне просто нужно зарегистрироваться для некоторых уведомлений, и я сделал ... Возвращение к видео сейчас, потому что я не могу вспомнить подробные сведения о том, какие уведомления отправляются и как реагировать на них. По крайней мере, поведение совместимо на обеих платформах. Как ни странно, ни один из этих документов не появляется в диалоговом окне File-Open Mac Apps, в котором перечислены все документы в каталоге документов iCloud, что не так странно.

enter image description here

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
//FLOG(@" got_persistentStoreCoordinator is %@", _persistentStoreCoordinator); 
FLOG(@" calling addPersistentStoreWithType for path %@", [_storeURL path]); 
NSString *fileName = [[_storeURL URLByDeletingPathExtension] lastPathComponent]; 
FLOG(@" setting NSPersistent for path %@", [_storeURL path]); 
@try { 
    store = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:_storeURL 
                  options:@{NSPersistentStoreUbiquitousContentNameKey:fileName, 
                   NSMigratePersistentStoresAutomaticallyOption:@YES, 
                   NSInferMappingModelAutomaticallyOption:@YES, 
                   NSSQLitePragmasOption:@{ @"journal_mode" : @"DELETE" }} 
                   error:&error]; 

...

+0

Я использовал полный URL и мог вернуться. В видео WWDC 2013 207 они предоставляют только значение NSString, которое представляет компонент пути подпапки, поэтому я экспериментировал с этим путем, чтобы увидеть, будут ли выполняться миграции. – dtrotzjr

+0

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

+0

Я мог бы попытаться сохранить документы в магазине ubiquity и посмотреть, все еще работают резервные хранилища.Я пытался изо всех сил избегать этого, но я продолжаю сталкиваться с проблемами, когда их хранение не приводит к проблемам, обнаруживающим, какие документы существуют в облаке, просто по транзакционным квитанциям, найденным во время запроса метаданных. – dtrotzjr

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