2

1 つのデバイスでアプリから iCloud コンテナーに単純なファイルを書き込むことができず、2 番目のデバイスでアプリを初めて実行したときに同じファイルを正常に読み取ることができません。

このテスト シナリオは、新しくリセットされたデバイスのペアで空の Ubiquity コンテナーを使用して開始しました。以下は、私が抱えている問題を示すテスト ケース コードとコンソール ログです。以下のコードはすべてバックグラウンド スレッドで実行されます。

最初のデバイスにテスト ケースをインストールして実行します。このコードは、ユビキタス コンテナーで特定のファイルを探し、見つからない場合は作成します。明らかに、これは最初のデバイスで初めて実行するときに予想されます。私は、アプリが新たにインストールされて 2 番目のデバイスで実行されたときに、最初のデバイスで作成されたファイルの内容を見つけて読み取ることができることを期待 (期待) していました。リセットされたデバイスに新しくインストールされたアプリは、既存のファイルを見つけて読み取ることができず、新しいファイルを作成する必要があると常に考えているようです。残念ながら、ユビキタス コンテナー内のファイルが既に存在する場合は置き換えられます。

ただし、最初の試行 (2 番目のデバイスで) がファイルの検索と読み取りに失敗した後、アプリを削除し、再インストールしてから同じデバイスで再実行すると、ファイルが検出され、読み取ることができます。その現在の内容。アプリを最初に実行すると、ファイルがユビキタス キャッシュに読み込まれるように見えますが、アプリで見つけられる状態ではありません。アプリの 2 回目の実行では、キャッシュ内のファイルが見つかったようです。

iOSデバイスでファイルのダウンロードを開始することになっていることは知っていますが、デバイスで初めて、「ファイルが見つかりません」と報告されます。ここで他に何かする必要がありますか?それとも、これは新しいバグまたは既知のバグのように見えますか?

次のコードは、ユビキタス コンテナー内のトークン ファイルの存在を判断し、読み取り可能であることを確認するために使用されます。

NSError *error;
BOOL rc;

NSFileManager *fm = [[NSFileManager alloc] init];
NSURL *ubiquityURL = [fm URLForUbiquityContainerIdentifier:nil];
NSURL *tokenURL = [ubiquityURL URLByAppendingPathComponent:@"iCloudTokenFile"];

NSLog(@"isTokenFilePresentAtUrl: Entered for Device Name: %@", [[UIDevice currentDevice] name]);

error = nil;
rc = [fm startDownloadingUbiquitousItemAtURL:tokenURL error:&error];
NSLog(@"startDownloadingUbiquitousItemAtURL: %d Error: %@(%d)", rc, error.domain, error.code);

rc = [fm isUbiquitousItemAtURL:tokenURL];
NSLog(@"isUbiquitousItemAtURL: %d", rc);

NSNumber *isUbiquitousItem = nil;
error = nil;
rc = [tokenURL getResourceValue:&isUbiquitousItem forKey:NSURLIsUbiquitousItemKey error:&error];
NSLog(@"getResourceValue: %d isUbiquitousItem: %@ Error: %@(%d)", rc, isUbiquitousItem, error.domain, error.code);

NSNumber *isDownloading = nil;
error = nil;
rc = [tokenURL getResourceValue:&isDownloading forKey:NSURLUbiquitousItemIsDownloadingKey error:&error];
NSLog(@"getResourceValue: %d isDownloading: %@ Error: %@(%d)", rc, isDownloading, error.domain, error.code);

NSNumber *isDownloaded = nil;
error = nil;
rc = [tokenURL getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:&error];
NSLog(@"getResourceValue: %d isDownloaded: %@ Error: %@(%d)", rc, isDownloaded, error.domain, error.code);

次のコードは、ユビキタス コンテナーからトークン ファイルを読み取ろうとするために使用されます。

__block BOOL success = NO;
__block NSError *error = nil;

NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fc coordinateReadingItemAtURL:tokenURL
                       options:NSFileCoordinatorReadingWithoutChanges
                         error:&error
                    byAccessor:^(NSURL *newURL)
 {
     NSLog(@"readTokenFileFromUrl: Trying to read Token File.");

     NSNumber *isDownloaded = nil;
     error = nil;
     BOOL rc = [tokenURL getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:&error];
     NSLog(@"getResourceValue: %d isDownloaded: %@ Error: %@(%d)", rc, isDownloaded, error.domain, error.code);

     NSString *uuidString =  nil;
     NSError *blockerror = nil;
     uuidString = [NSString stringWithContentsOfURL:newURL
                                           encoding:NSUTF8StringEncoding
                                              error:&blockerror];

     NSLog(@"readTokenFileFromUrl: Token read from file: %@", uuidString);
 }];

次のコードは、既存のトークン ファイルを読み取ることができない場合にトークン ファイルをユビキタス コンテナーに書き込むために使用されます。このコードは、最初のデバイスで 1 回だけ実行されると予想していました。

NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSError *error = nil;
[fc coordinateWritingItemAtURL:tokenURL
                       options:NSFileCoordinatorWritingForReplacing
                         error:&error
                    byAccessor:^(NSURL *newURL)
 {
     NSUUID *uuid = [[NSUUID alloc] init];
     NSString *uuidString = [uuid UUIDString];

     NSError *blockerror = nil;
     NSLog(@"writeTokenFileToUrl: Writing token to file: %@", uuidString);

     [uuidString writeToURL:newURL
                 atomically:YES
                   encoding:NSUTF8StringEncoding
                      error:&blockerror];
 }];

アプリは「Red iPod touch」に初めてインストールして実行します。

isTokenFilePresentAtUrl: Entered for Device Name: Red iPod touch 
startDownloadingUbiquitousItemAtURL: 0 Error: NSCocoaErrorDomain(4) 
isUbiquitousItemAtURL: 0 
getResourceValue: 0 isUbiquitousItem: (null) Error: NSPOSIXErrorDomain(2) 
getResourceValue: 0 isDownloading: (null) Error: NSPOSIXErrorDomain(2) 
getResourceValue: 0 isDownloaded: (null) Error: NSPOSIXErrorDomain(2) 
readTokenFileFromUrl: Trying to read Token File. 
getResourceValue: 0 isDownloaded: (null) Error: NSPOSIXErrorDomain(2) 
readTokenFileFromUrl: Token from File: (null) 
readTokenFileFromUrl: Error reading uuid Token from File: NSCocoaErrorDomain(260) 
loadiCloudStore: isUbiquitousItemAtURL: Token File actually does not appear to be present. 
writeTokenFileToUrl: Writing token to file: 6AAA8D81-4BB5-4BF4-AD31-E152D3BADD13

この時点で、developer.icloud.com Web サイトを介して、ファイルが Ubiquity Container に存在することが確認されます。アプリは、「Blue iPod touch」という名前の 2 番目のデバイスに初めてインストールされ、実行されます。

isTokenFilePresentAtUrl: Entered for Device Name: Blue iPod touch
startDownloadingUbiquitousItemAtURL: 0 Error: NSCocoaErrorDomain(4)
isUbiquitousItemAtURL: 0
getResourceValue: 0 isUbiquitousItem: (null) Error: NSPOSIXErrorDomain(2)
getResourceValue: 0 isDownloading: (null) Error: NSPOSIXErrorDomain(2)
getResourceValue: 0 isDownloaded: (null) Error: NSPOSIXErrorDomain(2)
readTokenFileFromUrl: Trying to read Token File.
getResourceValue: 0 isDownloaded: (null) Error: NSPOSIXErrorDomain(2)
readTokenFileFromUrl: Token from File: (null)
readTokenFileFromUrl: Error reading uuid Token from File: NSCocoaErrorDomain(260)

このテストでは、アプリは読み取りを試行した後に停止され、トークン ファイルの書き込みまたは置換を試行することはできません。その後、アプリは強制終了され、削除され、再インストールされ、Blue iPod touch で再び実行されます。

isTokenFilePresentAtUrl: Entered for Device Name: Blue iPod touch
startDownloadingUbiquitousItemAtURL: 1 Error: (null)(0)
isUbiquitousItemAtURL: 1
getResourceValue: 1 isUbiquitousItem: 1 Error: (null)(0)
getResourceValue: 1 isDownloading: 1 Error: (null)(0)
getResourceValue: 1 isDownloaded: 0 Error: (null)(0)
readTokenFileFromUrl: Trying to read Token File.
getResourceValue: 1 isDownloaded: 0 Error: (null)(0)
readTokenFileFromUrl: Token read from file: 6AAA8D81-4BB5-4BF4-AD31-E152D3BADD13

今回は、期待される内容のファイルを見つけて読み取ります。

4

1 に答える 1

0

まあ、私はあきらめませんでした。今では、この問題を回避するための許容できる方法があると思います。ソリューションの鍵は、2 番目のデバイスが、最初のデバイスによってユビキタス コンテナーに書き込まれたトークン ファイルを正常に検出できることであり、ファイル自体を書き込もうとしないことです。

ここに私のために働くステップがあります:

  • すぐにコンテナーからトークン ファイルを読み取ってみます。
  • 成功した場合は、ファイルを使用して残りの手順を無視します。
  • それ以外の場合は、述語が 2 つの特定のファイル名 (読み取ろうとしているトークン ファイルと「ダミー」ファイル) でトリガーされるメタ データ クエリを開始します。
  • ここで、ダミーのファイル名を使用して、ユビキタス コンテナーにファイルを書き込みます。
  • メタ データ クエリの結果が到着したら、報告されたファイルのアップロード/ダウンロード ステータスを確認します。
  • クエリでトークン ファイルが表示されたと報告された場合、これは最初のデバイスではなく、成功するまでファイルの読み取りを試行し続ける必要があります。少し時間がかかるかもしれませんが、最終的には読み上げられます。
  • メタ データ クエリでダミー ファイルが完全にアップロードされたと報告され、まだトークン ファイルの兆候がない場合は、これが最初のデバイスであると想定しても安全であり、トークン ファイルを書き込めます。
  • トークンを使用する前に、トークン ファイルのステータスが完全にアップロードされるまで待つと便利です。そうしないと、ネットワークに問題がある場合、このプロセスを開始している別のデバイスも同じことを行い、それが最初のデバイスであると考える可能性があります。

ダミー ファイルをユビキタス コンテナに書き込むと、メタ データ クエリが「キック スタート」し、2 番目のデバイスにトークン ファイルが存在することを報告できるようになるようです。これがないと、メタ データ クエリは、最初のデバイス以外にトークン ファイルが存在することを報告しません。

于 2012-12-11T01:03:13.943 に答える