簡體   English   中英

如何使用 iCloud 存儲和同步應用程序文件

[英]How to use iCloud to store and sync app files

我已經有一個 iPhone 應用程序,可以將數據存儲在本地文檔文件夾中的文件中。 現在我了解了 iCloud 技術,我的第一個問題是:當我有時檢查新版本時,有沒有辦法將 iCloud 用作目錄?

我的意思是:我可以避免使用 UIDocument、文件協調器和文件展示器嗎? 我只想知道是否可以將 iCloud 視為一個特殊的文件夾,並且只使用 NSFileManager 來推送和檢索文件。

最后一點:我不使用 Core Data 或任何數據庫,我只有一個數據文件。

編輯:

我已經閱讀了 Apple iCloud 官方文檔,所以不要將我鏈接到它們。 我只需要一些代碼示例。

對我來說“有效”的方法很簡單:

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,所以不能說它會被“批准”到應用程序商店(如果他們發現或關心......)

我知道你的感受,iCloud 有點令人生畏。 但是,我認為沒有辦法繞過 UIDocument、文件協調器等,而只能將 iCloud 用作一個簡單的文件夾。

如果您正在尋找易於理解的示例代碼,請查看這篇文章:

iCloud 基礎知識和代碼示例

我包含了一個完整的示例代碼,它涵蓋了 iCloud 的最低要求,並且幾乎像目錄一樣使用它。 也許這會讓你使用 UIDocument、文件協調器等不那么令人生畏。

但是,像你一樣,我希望有一種更簡單、更兼容的方式來與舊的紀錄片文件​​夾想法相匹配。 但是,由於這是 iCloud,並且 iCloud 還做了幾件事(例如在不同設備上保持所有內容同步,不斷更新到雲等),因此將無法繞過 UIDocument 等。

您可以使用 NSFileManager 將單個文件上傳到 iCloud。 我在我的博客上發布了有關如何執行此操作完整演練,但這是相關的 NSFileManager 代碼:

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

沒有真正的方法可以使用 UIDocument。 我嘗試在我第一次使用 iCloud 時做到這一點,但結果證明沒有 UIDocument 是一場災難。 一開始使用 UIDocument 似乎有很多額外的工作,但事實並非如此。

您可以在一個小時內輕松地將 UIDocument 子類化,並使其適用於任何類型的文件(只需將content屬性設置為 NSData)。 與標准文件系統相比,它還提供了許多好處:

  • 變更追蹤
  • 文件沖突解決
  • 文檔狀態支持
  • 增強的保存/打開/關閉功能

老實說,花一兩個小時閱讀 Apple 文檔然后使用它是非常值得的。 可以在Apple 的開發人員文檔 中找到有關 iCloud 文檔存儲的優秀入門文章。


我編寫了一個 UIDocument 子類,它可以處理任何類型的文件(特別是 NSData)。 您可以在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 文檔同步項目使存儲和同步應用程序文件變得非常容易:

用一行代碼的方式將 iCloud 集成到 iOS 文檔項目中。 快速輕松地從 iCloud 同步、上傳、管理和刪除文檔。 也有助於使 iCloud 對開發人員“正常工作”。

在幾乎所有 iCloud 文檔同步方法中,您所要做的就是將文件數據作為參數傳遞,然后它會處理其余的(保存、同步等)。

免責聲明:我是開源項目 iCloud 文檔同步的貢獻開發人員。 但是,我相信這個項目會對您有所幫助,並且與這個問題相關。 這不是促銷或廣告。

使用此代碼:

+ (NSString *)Pathsave {
    NSString *os5 = @"5.0";

    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

    if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedAscending) {
       // Lower than 4
        return path;
    } else if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedDescending) {
        // 5.0.1 and above        
        return path;
    } else {
        // iOS 5
        path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
        return path;
    }

    return nil;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM