[iCloud]項(xiàng)目?jī)?nèi)啟用iCloud及iCloud Documents

CloudKit的數(shù)據(jù)存儲(chǔ)分為兩種:
一種是使用iCloudKit,其API的使用有點(diǎn)像sqlite;
一種是使用iCloud Documents, 這個(gè)有點(diǎn)像APP的本地沙盒;

真對(duì)第一種可參考[iCloud]項(xiàng)目?jī)?nèi)啟用iCloud及CloudKit Dashboard介紹了解,今天主要講的是第二種: iCloud Documents;

一, 啟用iCloud

首先,新建項(xiàng)目后,要確保你的Apple ID是一個(gè)有效的開(kāi)發(fā)者賬號(hào);并在General -->Identity 下的Team選項(xiàng),選擇你的開(kāi)發(fā)者賬號(hào),這里的開(kāi)發(fā)者賬號(hào),必須是有效的開(kāi)發(fā)者賬號(hào),并確保你的Bundle Identifier是唯一的;
然后,設(shè)置權(quán)限和容器,選擇Capabilities-->啟用iCloud,如下圖所示:

Capabilities啟用iCloud

如果之前沒(méi)有選擇開(kāi)發(fā)者賬號(hào)的話,這時(shí),可能需要你登陸開(kāi)發(fā)者賬號(hào);
最后,勾選iCloud Documents,這時(shí)Containers下的選項(xiàng)就可點(diǎn)了,選擇Use default container:

編譯一下,沒(méi)有錯(cuò)誤,即開(kāi)啟成功!

注意: 這里的開(kāi)發(fā)者賬號(hào)要有相應(yīng)的證書(shū),而且證書(shū)的Apple ID中啟用了iCloud:

appleid啟用iCloud

如果,已有id, 可以點(diǎn)擊Edit進(jìn)行啟用.

二. 數(shù)據(jù)操作

今天要講的這種操作數(shù)據(jù)的方法主要是使用了NSFileManager,當(dāng)您看到這個(gè),是不是就安心了許多? 是的, 和操作本地文件有很多相似的地方, 只是使用的API不同.

2.1 檢查iCloud是否可用

在進(jìn)行數(shù)據(jù)操作之前,一定要確保iCloud是可用的, 如果不可用, 豈不是在做無(wú)用功?這里使用的方法主要是下面這個(gè):

- (nullable NSURL *)URLForUbiquityContainerIdentifier:(nullable NSString *)containerIdentifier

這個(gè)方法會(huì)返回一個(gè)URL地址, 如果iCloud不可用,返回的將會(huì)是nil,我們以此來(lái)判斷iCloud是否可用.
參數(shù)containerIdentifier:
在我們啟用iCloud的時(shí)候,即Capabilities-->iCloud-->Containers,這里我們選擇的是默認(rèn)的容器, 當(dāng)然也可以點(diǎn)擊" + "來(lái)添加新的容器,然后把這個(gè)新的容器的名字設(shè)置為這個(gè)參數(shù).
一般,一個(gè)APP只要一個(gè)容器就夠了, 這里使用默認(rèn)的即可,不需要新建,所以,這里直接傳nil,即: 找到的第一個(gè)可用的容器即可. 完整的判斷方法為:

+ (BOOL)iCloudEnable {
    
    // 獲得文件管理器
    NSFileManager *manager = [NSFileManager defaultManager];
    
    // 判斷iCloud是否可用
    // 參數(shù)傳nil表示使用默認(rèn)容器
    NSURL *url = [manager URLForUbiquityContainerIdentifier:nil];
    // 如果URL不為nil, 則表示可用
    if (url != nil) {
        
        return YES;
    }
    
    NSLog(@"iCloud 不可用");
    return NO;
}
2.2 獲取完整的URL地址(文件在iCloud的保存位置)

在驗(yàn)證iCloud可用之后, 接下來(lái)就要獲取這個(gè)iCloud的保存文件的位置, 就相當(dāng)于本地沙盒的路徑. 其實(shí)上面已經(jīng)獲取了URL地址, 相當(dāng)于本地沙盒的根目錄, 我們一般是把文件保存在Documents文件夾下, iCloud也有個(gè)Documents,只需要把上面的代碼稍作修改即可:

+ (NSURL *)iCloudFilePathByName:(NSString *)name {
    
    NSFileManager *manager = [NSFileManager defaultManager];
    
    // 判斷iCloud是否可用
    // 參數(shù)傳nil表示使用默認(rèn)容器
    NSURL *url = [manager URLForUbiquityContainerIdentifier:nil];
    
    if (url == nil) {
        
        return nil;
    }
    
    url = [url URLByAppendingPathComponent:@"Documents"];
    NSURL *iCloudPath = [NSURL URLWithString:name relativeToURL:url];
    
    return iCloudPath;
}

這里的參數(shù)name,就是保存在iCloud時(shí)的文件名稱.

2.3 獲取本地沙盒的路徑

這個(gè)路徑是為后面保存到iCloud的時(shí)候使用的, 保存的方法有一個(gè)參數(shù), 是傳的需要保存文件的URL, 我這里是先將要保存的文件寫(xiě)入本地沙盒( 其實(shí)一般需要備份的文件都是在本地沙盒的 ), 然后再上傳到iCloud:

+ (NSString *)localFilePath:(NSString *)name {
    
    // 得到本程序沙盒路徑
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:name];
    
    return filePath;
}
2.4 保存文件到iCloud

在保存到iCloud之前需要先判斷當(dāng)前的文件在iCloud是否存在:

- (BOOL)isUbiquitousItemAtURL:(NSURL *)url

存在的話,可以直接使用寫(xiě)入文件的方式進(jìn)行將數(shù)據(jù)保存到iCloud:

- (BOOL)writeToURL:(NSURL *)url options:(NSDataWritingOptions)writeOptionsMask error:(NSError **)errorPtr

這里我是轉(zhuǎn)為NSData來(lái)寫(xiě)入的, 其實(shí)還可以使用NSArray, NSDictionary等可以直接歸檔的方式寫(xiě)入. 因?yàn)楹芏啾镜匚募伎梢允褂?strong>NSData ,所以這里就直接使用這個(gè)比較通用的方式來(lái)寫(xiě)入了.

如果iCloud中不存在,就要使用下面的額方法來(lái)寫(xiě)入:

- (BOOL)setUbiquitous:(BOOL)flag itemAtURL:(NSURL *)url destinationURL:(NSURL *)destinationURL error:(NSError **)error

這里主要是urldestinationURL, 前者是iCloudURL, 后者是本地文件的URL, 也就是上面準(zhǔn)備的.
我這里上傳的操作是這樣的:

// private method
+ (void)uploadToiCloud:(NSString *)name localFile:(NSString *)file resultBlock:(uploadBlock)block {
    
    NSURL *iCloudUrl = [self iCloudFilePathByName:name];
    NSString *localFilePath = file;
    if ([file componentsSeparatedByString:@"/"].count < 2) {
        
        localFilePath = [self localFilePath:file];
    }
    
    NSFileManager *manager  = [NSFileManager defaultManager];
    
    // 判斷本地文件是否存在
    if ([manager fileExistsAtPath:localFilePath]) {
        
        NSData *data = [NSData dataWithContentsOfFile:localFilePath];
        // 判斷iCloud里該文件是否存在
        if ([manager isUbiquitousItemAtURL:iCloudUrl]) {
            
            NSError *error = nil;
            [data writeToURL:iCloudUrl options:NSDataWritingAtomic error:&error];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                block(error);
            });
            
        } else {
            
            NSURL *fileUrl = [NSURL fileURLWithPath:localFilePath];
            
            NSError *error = nil;
            [manager setUbiquitous:YES itemAtURL:fileUrl destinationURL:iCloudUrl error:&error];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                block(error);
            });
        }
    }
}

簡(jiǎn)單的加了一些判斷邏輯, 在進(jìn)行這個(gè)操作的時(shí)候, 最好使用異步, 大家也看到了, 這是一個(gè)私有的方法, 在進(jìn)行這個(gè)操作之前, 我又進(jìn)行了一層的封裝, 只是加了一些判斷:

+ (void)uploadToiCloud:(NSString *)name file:(id)file resultBlock:(uploadBlock)block {
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        
        if ([file isKindOfClass:[NSString class]]) {
            
            [self uploadToiCloud:name localFile:file resultBlock:block];
        } else {
            
            NSString *path = [self localFilePath:@"temp.data"];
            
            NSError *error = nil;
            if ([file writeToFile:path options:NSDataWritingAtomic error:&error]) {
                
                [self uploadToiCloud:name localFile:path resultBlock:block];
            } else {
                
                dispatch_async(dispatch_get_main_queue(), ^{
                   
                    block(error);
                });
            }
        }
    });
}

只是判斷保存的文件如果不是路徑, 就先寫(xiě)入本地, 再使用上面的方法來(lái)上傳, 另外,在這里使用了GCD來(lái)異步執(zhí)行;

2.5 從iCloud同步數(shù)據(jù)到本地

同步到本地之前, 需要先判斷當(dāng)前的文件是否可用進(jìn)行同步, 這里使用了官方提供的一個(gè)方法:

// // 此方法是官方文檔提供,用來(lái)檢查文件狀態(tài)并下載
+ (BOOL)downloadFileIfNotAvailable:(NSURL*)file {
    NSNumber*  isIniCloud = nil;
    
    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:NSURLUbiquitousItemDownloadingStatusKey error:nil]) {
                if ([isDownloaded boolValue])
                    return YES;
                
                // Download the file.
                NSFileManager*  fm = [NSFileManager defaultManager];
                if (![fm startDownloadingUbiquitousItemAtURL:file error:nil]) {
                    return NO;
                }
                return YES;
            }
        }
    }
    
    // Return YES as long as an explicit download was not started.
    return YES;
}

自己需要做的, 就是在解析數(shù)據(jù)之前, 檢查一下這個(gè)狀態(tài), 然后獲取/解析數(shù)據(jù):

+ (void)downloadFromiCloud:(NSString *)name responsBlock:(downloadBlock)block {
    
    NSURL *iCloudUrl = [self iCloudFilePathByName:name];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        
        if ([self downloadFileIfNotAvailable:iCloudUrl]) {
            
            // 先嘗試轉(zhuǎn)為數(shù)組
            NSArray *array = [[NSArray alloc]initWithContentsOfURL:iCloudUrl];
            
            if (array != nil) {
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    
                    block(array);
                });
                
            } else {
                
                // 如果數(shù)組為nil, 再嘗試轉(zhuǎn)為字典
                NSDictionary *dic = [[NSDictionary alloc]initWithContentsOfURL:iCloudUrl];
                if (dic != nil) {
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        block(dic);
                    });
                } else {
                    // 如果字典為nil, 最后嘗試轉(zhuǎn)為NSData
                    NSData *data = [[NSData alloc]initWithContentsOfURL:iCloudUrl];
                    if (data != nil) {
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            block(data);
                        });
                    } else {
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            block(nil);
                        });
                    }
                }
            }
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                
                block(nil);
            });
        }
    });
}

我這里使用的方法, 就比較笨了. 其實(shí), 文件上傳時(shí)的類型我們是可控的, 這樣在解析的時(shí)候就會(huì)比較有針對(duì)性, 不用這么一個(gè)個(gè)去檢查判斷.

好了, 以上便是使用NSFileManager 進(jìn)行的iCloud 同步操作, 保存成功與否, 可在手機(jī)"設(shè)置-->iCloud-->儲(chǔ)存空間-->管理儲(chǔ)存空間" 來(lái)查看, 這里列舉了所有已備份到iCloudAPP數(shù)據(jù).
最后附上一個(gè)demo: LZiCloudDemo
里面有兩種用法, 一個(gè)是使用NSFileManager, 一個(gè)是使用UIDocument, 關(guān)于UIDocument, 可參考這篇文章: [iOS]文檔操作之UIDocument

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市照弥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粱胜,死亡現(xiàn)場(chǎng)離奇詭異亡嫌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)泵额,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)携添,“玉大人嫁盲,你說(shuō)我怎么就攤上這事⌒皆ⅲ” “怎么了亡资?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)向叉。 經(jīng)常有香客問(wèn)我锥腻,道長(zhǎng),這世上最難降的妖魔是什么母谎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任瘦黑,我火速辦了婚禮,結(jié)果婚禮上奇唤,老公的妹妹穿的比我還像新娘幸斥。我一直安慰自己,他們只是感情好咬扇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布甲葬。 她就那樣靜靜地躺著,像睡著了一般懈贺。 火紅的嫁衣襯著肌膚如雪经窖。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天梭灿,我揣著相機(jī)與錄音画侣,去河邊找鬼。 笑死堡妒,一個(gè)胖子當(dāng)著我的面吹牛配乱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼搬泥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桑寨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起佑钾,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤西疤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后休溶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扰她,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年兽掰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徒役。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孽尽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出忧勿,到底是詐尸還是另有隱情杉女,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布鸳吸,位于F島的核電站熏挎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏晌砾。R本人自食惡果不足惜坎拐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望养匈。 院中可真熱鬧哼勇,春花似錦、人聲如沸呕乎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)猬仁。三九已至帝璧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逐虚,已是汗流浹背聋溜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叭爱,地道東北人撮躁。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像买雾,于是被迫代替她去往敵國(guó)和親把曼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杨帽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)嗤军,斷路器注盈,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 創(chuàng)建自定義文檔對(duì)象 基于文檔的應(yīng)用程序必須具有代表和管理文檔數(shù)據(jù)的UIDocument子類的實(shí)例。本章討論了覆蓋大...
    nicedayCoco閱讀 1,434評(píng)論 0 3
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,822評(píng)論 6 342
  • 通過(guò)iOS 8app extensions,我們可以選擇多種方式去分享我們app的功能叙赚。Document Prov...
    _淺墨_閱讀 7,194評(píng)論 4 12
  • UIKit框架為管理多個(gè)文檔的應(yīng)用程序提供支持老客,每個(gè)文檔包含存儲(chǔ)在應(yīng)用程序沙箱或iCloud中的文件中的唯一數(shù)據(jù)集...
    nicedayCoco閱讀 3,716評(píng)論 0 1