Сохранить документы iOS 8 на iCloud Drive

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

UPDATE2

В моем коде есть следующее, чтобы вручную сохранить документ на iCloud Drive:

- (void)initializeiCloudAccessWithCompletion:(void (^)(BOOL available)) completion {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        self.ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
        if (self.ubiquityURL != nil) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"iCloud available at: %@", self.ubiquityURL);
                completion(TRUE);
            });
        }
        else {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"iCloud not available");
                completion(FALSE);
            });
        }
    });
}
if (buttonIndex == 4) {



     [self initializeiCloudAccessWithCompletion:^(BOOL available) {

        _iCloudAvailable = available;

        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

        NSString *documentsDirectory = [paths objectAtIndex:0];

        NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:selectedCountry];

        NSURL* url = [NSURL fileURLWithPath: pdfPath];


        [self.manager setUbiquitous:YES itemAtURL:url destinationURL:self.ubiquityURL error:nil];


    }];

       }

У меня есть права, установленные для идентификатора приложения и в самом XCode. Я нажимаю кнопку, чтобы сохранить на iCloud Drive, и не появляется никаких ошибок, приложение не падает, но на моем Mac в iCloud Drive ничего не отображается. Приложение работает на моем iPhone 6 Plus через Test Flight при использовании iOS 8.1.1.

Если я запускаю его на симуляторе (я знаю, что он не будет работать из-за того, что iCloud Drive не работает с симулятором), я получаю ошибку сбоя: 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[3]'

2 ответа

Решение

Ну, ты сам заинтересовал меня этим вопросом, и в результате я потратил много времени на этот вопрос, но теперь, когда он у меня работает, я надеюсь, что он тебе тоже поможет!

Файл на моем Mac

Чтобы увидеть, что на самом деле происходит в фоновом режиме, вы можете взглянуть на ~/Library/Mobile Documents/, поскольку это папка, где файлы в конечном итоге будут отображаться. Еще одна очень крутая утилита brctl, чтобы отслеживать, что происходит на вашем Mac после сохранения файла в iCloud. Бежать brctl log --wait --shorten из окна терминала, чтобы начать журнал.

Первое, что нужно сделать после включения возможности iCloud (с выбранными документами iCloud), это предоставить информацию для поддержки iCloud Drive ( Включение поддержки iCloud Drive). Мне также пришлось столкнуться с версией пакета, прежде чем снова запустить приложение; Мне понадобилось время, чтобы понять это. Добавьте следующее к вашему info.plist:

<key>NSUbiquitousContainers</key>
<dict>
    <key>iCloud.YOUR_BUNDLE_IDENTIFIER</key>
    <dict>
        <key>NSUbiquitousContainerIsDocumentScopePublic</key>
        <true/>
        <key>NSUbiquitousContainerSupportedFolderLevels</key>
        <string>Any</string>
        <key>NSUbiquitousContainerName</key>
        <string>iCloudDriveDemo</string>
    </dict>
</dict>

Далее код:

- (IBAction)btnStoreTapped:(id)sender {
    // Let's get the root directory for storing the file on iCloud Drive
    [self rootDirectoryForICloud:^(NSURL *ubiquityURL) {
        NSLog(@"1. ubiquityURL = %@", ubiquityURL);
        if (ubiquityURL) {

            // We also need the 'local' URL to the file we want to store
            NSURL *localURL = [self localPathForResource:@"demo" ofType:@"pdf"];
            NSLog(@"2. localURL = %@", localURL);

            // Now, append the local filename to the ubiquityURL
            ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];
            NSLog(@"3. ubiquityURL = %@", ubiquityURL);

            // And finish up the 'store' action
            NSError *error;
            if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
                NSLog(@"Error occurred: %@", error);
            }
        }
        else {
            NSLog(@"Could not retrieve a ubiquityURL");
        }
    }];
}

- (void)rootDirectoryForICloud:(void (^)(NSURL *))completionHandler {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:@"Documents"];

        if (rootDirectory) {
            if (![[NSFileManager defaultManager] fileExistsAtPath:rootDirectory.path isDirectory:nil]) {
                NSLog(@"Create directory");
                [[NSFileManager defaultManager] createDirectoryAtURL:rootDirectory withIntermediateDirectories:YES attributes:nil error:nil];
            }
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            completionHandler(rootDirectory);
        });
    });
}

- (NSURL *)localPathForResource:(NSString *)resource ofType:(NSString *)type {
    NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *resourcePath = [[documentsDirectory stringByAppendingPathComponent:resource] stringByAppendingPathExtension:type];
    return [NSURL fileURLWithPath:resourcePath];
}

У меня есть файл с именем demo.pdf хранится в папке "Документы", которую я буду "загружать".

Я выделю некоторые части:

URLForUbiquityContainerIdentifier: предоставляет корневой каталог для хранения файлов. Если вы хотите, чтобы они отображались в de iCloud Drive на вашем Mac, вам необходимо сохранить их в папке "Документы", поэтому здесь мы добавляем эту папку в корневой каталог:

NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:@"Documents"];

Вам также нужно добавить имя файла в URL, здесь я копирую имя файла из localURL (который является demo.pdf):

// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];

И это в основном все...

В качестве бонуса, проверьте, как вы можете предоставить NSError указатель для получения информации о потенциальной ошибке:

// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
    NSLog(@"Error occurred: %@", error);
}

Если вы собираетесь работать с UIDocument и iCloud, это руководство от Apple довольно неплохо: https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/Introduction/Introduction.html

ИЗДАНО: Не знаю лучшего руководства, так что это может помочь:

Вам нужно будет получить ubiquityURL, используя URLForUbuiquityContainerIdentifier функция на NSFileManager (что должно быть сделано асинхронно). Как только это будет сделано, вы можете использовать код, подобный следующему, для создания вашего документа.

NSString* fileName = @"sampledoc";
NSURL* fileURL = [[self.ubiquityURL URLByAppendingPathComponent:@"Documents" isDirectory:YES] URLByAppendingPathComponent:fileName isDirectory:NO];

UIManagedDocument* document = [[UIManagedDocument alloc] initWithFileURL:fileURL];

document.persistentStoreOptions = @{
                    NSMigratePersistentStoresAutomaticallyOption : @(YES),
                    NSInferMappingModelAutomaticallyOption: @(YES),
                    NSPersistentStoreUbiquitousContentNameKey: fileName,
                    NSPersistentStoreUbiquitousContentURLKey: [self.ubiquityURL URLByAppendingPathComponent:@"TransactionLogs" isDirectory:YES]
};

[document saveToURL:fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {

}];

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

** Редактировать 2 **

Похоже, вы пытаетесь сохранить файл PDF, что не совсем то, что Apple считает "документом" с точки зрения синхронизации iCloud. Нет необходимости использовать UIManagedDocument. Удалите последние 3 строки вашего обработчика завершения и вместо этого просто используйте NSFileManager's setUbiquitous:itemAtURL:destinationURL:error: функция. Первый URL должен быть локальным путем к PDF. Второй URL должен быть путем в контейнере ubiquiuty, чтобы сохранить как.

Вам также может понадобиться заглянуть в NSFileCoordinator, возможно. Я думаю, что это руководство от Apple может быть наиболее актуальным: https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/iCloud/iCloud.html

Другие вопросы по тегам