web-dev-qa-db-ja.com

iCloudを使用してアプリファイルを保存および同期する方法

ローカルドキュメントフォルダー内のファイルにデータを保存するiPhoneアプリを既に持っています。今、私はiCloudテクノロジーについて学び、私の最初の質問は、時々新しいバージョンをチェックするときにiCloudをディレクトリとして使用する方法はありますか?

つまり、UIDocument、ファイルコーディネーター、およびファイルプレゼンターの使用を回避できますか? iCloudを特別なフォルダーのように扱い、NSFileManagerを使用してファイルをプッシュおよび取得できるかどうかを知りたいだけです。

最後の注意:コアデータやデータベースは使用せず、データファイルしかありません。

編集:

私はすでに公式のApple iCloudのドキュメントを読んでいるので、それらにリンクしないでください。いくつかのコード例だけが必要です。

33
edo42

ICloudは少し気が重いです。ただし、UIDocument、ファイルコーディネーターなどを回避し、iCloudを単純なフォルダーとして使用する方法はないと思います。

理解しやすいサンプルコードを探している場合は、この投稿をご覧ください。

iCloudの基本とコードサンプル

ICloudの最低限をカバーする完全なサンプルコードを含め、ディレクトリのように使用しています。おそらく、これによりUIDocument、ファイルコーディネーターなどを使用するのが難しくなります。

しかし、あなたのように、古き良きドキュメンタリーフォルダーのアイデアとより簡単で互換性のある方法があればいいのにと思います。ただし、これはiCloudであり、iCloudがさらにいくつかのこと(異なるデバイスですべての同期を維持する、クラウドに常に更新するなど)を行うため、UIDocumentなどを回避する方法はありません。

16
n.evermind

私にとって「機能する」ものは簡単です。

NSFileManager *fm = [NSFileManager defaultManager];

NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];

if (ubiq == nil) {
    return NO;
}

NSError *theError = nil;

[fm setUbiquitous:true itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:backupName] error:&theError];

Appleは、非UIスレッドを呼び出すように言っています。ファイルを「移動」させる。次のようにNSMetaDataQuery経由でクエリできます:

self.query = [[NSMetadataQuery alloc] init];
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K like '*.db'", NSMetadataItemFSNameKey];
[self.query setPredicate:pred];
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(queryDidFinishGathering:) 
                                             name:NSMetadataQueryDidFinishGatheringNotification 
                                           object:self.query];

[self.query startQuery];

- (void)queryDidFinishGathering:(NSNotification *)notification {
    NSMetadataQuery *query = [notification object];
    [query disableUpdates];
    [query stopQuery];

    [self loadData:query];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];

    self.query = nil; 
}

クエリ結果の列挙のサンプル:

- (void)loadData:(NSMetadataQuery *)query {
    [self.backups removeAllObjects];

    for (NSMetadataItem *item in [query results]) {
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
        [self.backups addObject:url.lastPathComponent];
    }

    [_table reloadData];

    [self.loadingBackupIndicator stopAnimating];
    self.loadingIndicatorLabel.text = [NSString stringWithFormat: @"%d backups found", [self.backups count]];
}

そして、具象ファイルの「ダウンロード」を開始するには:

NSFileManager *fm = [NSFileManager defaultManager];

NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];

if (ubiq == nil) {
    return NO;
}

NSError *theError = nil;

bool started = [fm startDownloadingUbiquitousItemAtURL:[[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:backupName] error:&theError];

NSLog(@"started download for %@ %d", backupName, started);

if (theError != nil) {
    NSLog(@"iCloud error: %@", [theError localizedDescription]);
}

「ダウンロード中」ファイルのチェック:

- (BOOL)downloadFileIfNotAvailable {
    NSNumber *isIniCloud = nil;

    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];

    NSURL *file = [[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:self.backupName];

    if ([file getResourceValue:&isIniCloud forKey:NSURLIsUbiquitousItemKey error:nil]) {
        // If the item is in iCloud, see if it is downloaded.
        if ([isIniCloud boolValue]) {
            NSNumber*  isDownloaded = nil;
            if ([file getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil]) {
                if ([isDownloaded boolValue]) {
                    [self.loadingBackupIndicator stopAnimating];
                    self.loadingIndicatorLabel.text = @"Downloaded";

                    ....

                    [[NSFileManager defaultManager] copyItemAtPath:[file path] toPath:restorePath error:&theError ];

                    ....

                    return YES;
                }

                self.loadingCheckTimer = [NSTimer timerWithTimeInterval:3.0f target:self selector:@selector(downloadFileIfNotAvailable) userInfo:nil repeats:NO];
                [[NSRunLoop currentRunLoop] addTimer:self.loadingCheckTimer forMode:NSDefaultRunLoopMode];

                return NO;
            }
        }
    }

    return YES;
}

ここで非常に生のスニペットを提供するために、コードがそれほど長くて申し訳ないと思っていました。上記のことをコードの生産品質とする意図はなく、単にコンセプトを共有するだけです。

私はまだアプリ内でそれをAppleに提出していないので、それがアプリストアに「承認」されるとは言えません(見つけたり気にしたりしたら...)

25

NSFileManagerを使用して、個々のファイルをiCloudにアップロードできます。私は 完全なウォークスルー をブログに投稿する方法を投稿しましたが、関連するNSFileManagerコードは次のとおりです。

NSURL *destinationURL = [self.ubiquitousURL URLByAppendingPathComponent:@"Documents/image.jpg"]
[[NSFileManager defaultManager] setUbiquitous:YES 
                                    itemAtURL:sourceURL
                               destinationURL:destinationURL
                                        error:&error]
14
samvermette

UIDocumentを実際に使用する方法はありません。私はiCloudの最初の使用の1つでそれをやろうとしましたが、UIDocumentがなければ災害になりました。最初はUIDocumentを使用することは多くの余分な作業のように思えますが、そうではありません。

1時間以内にUIDocumentを簡単にサブクラス化し、任意のタイプのファイルで動作させることができます(contentプロパティをNSDataとして設定するだけです)。また、標準のファイルシステムよりも多くの利点があります。

  • 変更追跡
  • ファイルの競合解決
  • ドキュメント状態のサポート
  • 強化された保存/開く/閉じる機能

正直なところ、Appleのドキュメントを1〜2時間読んでからそれを使用することは、時間と頭脳の力に見合う価値があります。iCloudドキュメントストレージに関する優れたスターター記事は Appleの開発者向けドキュメント


あらゆる種類のファイル(特にNSData)で動作するUIDocumentサブクラスを作成しました。 GitHub でUIDocumentサブクラスのコードを表示、ダウンロード、および変更できます。

ドキュメントを作成します。

// Initialize a document with a valid file path
iCloudDocument *document = [[iCloudDocument alloc] initWithFileURL:fileURL];

// Set the content of the document
document.contents = content;

// Increment the change count
[document updateChangeCount:UIDocumentChangeDone];

既存のドキュメントを保存します。

// Save and close the document
[document closeWithCompletionHandler:nil];

新しいドキュメントを保存します。

[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:nil];

NSMetadataQueryを使用して、iCloud内に保存されているすべてのファイルを同期することもできます。 Appleは、NSMetadataクエリを使用してアプリファイルを同期する非常に良い例です。また、これらの操作を実行する前にiCloudを確認してください(ヒント:NSFileManagerでubiquityIdentityTokenメソッドを使用) 。


iCloud Document Sync などのオープンソースライブラリの使用を検討することもできます。 iCloud Document Syncプロジェクトにより、アプリファイルの保存と同期が非常に簡単になります。

1行のコードメソッドを使用して、iCloudをiOSドキュメントプロジェクトに統合します。 iCloudからドキュメントをすばやく簡単に同期、アップロード、管理、削除します。開発者にとってもiCloudを「正常に動作させる」のに役立ちます。

ほとんどすべてのiCloud Document Syncメソッドでは、ファイルデータをパラメーターとして渡し、残りを処理(保存、同期など)するだけです。

[〜#〜]免責事項[〜#〜]:私は、オープンソースプロジェクトであるiCloud Document Syncに貢献する開発者です。しかし、このプロジェクトはあなたにとって有益であり、この質問に関連すると信じています。これはプロモーションや広告ではありません。

6
Samuel Spencer