CloudKit使用教程<一>

CloudKit使用教程<一>
CloudKit使用教程<二>

CloudKit是什么

  • 我的理解就是云端数据库,存储数据,提供简单的增删改查功能
  • 特点是方便简单,适合不懂后台的个人开发者.
  • 安全,毕竟是苹果自家的产品.不需要复杂的登录认证体系.
  • 国内也有类似的服务,免费版有一定限制,如优先级,请求数量,数据大小,及时性等.而目前苹果允许你使用 CloudKit 存储 10 GB 资源,100 M 数据库存储,每天 2 GB 流量;当你的用户数量增加的时候,这些免费额度也相应地增加到 1 PB 存储、10 TB 数据库存储,以及每天 200 TB 流量,几乎用不完.你感觉不够用的时候,你的用户量已经很庞大了....

集成

  • 设置好bundleID 和 team
  • 导入CloudKit框架
  • 在 XCode 中的 Capabilities 选项卡中找到 iCloud 选项,并打开开关:


    Paste_Image.png
  • 如果报错可以直接点击fix修复就可以了.或者在开发者中心配置appid(打开icloud,并手动添加容器),并且生成新的调试/发布证书,导入到本地.
  • 这样就完成 CloudKit 的设置了。设置完成后,我们点击 CloudKit Dashboard 按钮,可以打开 CloudKit 管理后台:


    Paste_Image.png
  • 关于共享容器,共享容器就是在同一个开发者不同app之间共享数据.在开发者中心 iCloud Containers这里添加新容器.


    Paste_Image.png
Paste_Image.png
  • 在上图选择sepcify custom containers,点击加好旁边的刷新按钮,就会出现新添加的容器.这个容器也可在其他app中被添加.
  • 也可以直接点击加号添加新容器,系统会自动添加iCloud前缀
  • 注意创建后的容器不能够删除,创建之前要想好,切记.

使用

支持的数据类型

Paste_Image.png

增加一条记录


    //创建索引ID
    CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"115"];
    
    //创建一条记录,type就是模型,与CloudKit 管理后台的Record types 一致,
    //如果后台没有,会自动添加相应的模型或者字段.
    CKRecord *artworkRecord = [[CKRecord alloc] initWithRecordType:@"Artwork" recordID:artworkRecordID];
    
    //设置模型的数据,和字典用法几乎一样
    artworkRecord[@"title" ] = @"MacKerricher State Park";
    artworkRecord[@"artist"] = @"Mei Chen";
    artworkRecord[@"address"] = @"Fort Bragg, CA";
    
    //公有数据库,我建议写成宏
    CKContainer *myContainer = [CKContainer defaultContainer];
    CKDatabase  *publicDatabase = [myContainer publicCloudDatabase];
    
    //私有数据库
    CKContainer *myContainer = [CKContainer defaultContainer];
    CKDatabase  *privateDatabase = [myContainer privateCloudDatabase];
    
    //自定义的容器,比如上图中的共享容器,需要id标识
    CKContainer *shareContainer = [CKContainer containerWithIdentifier:@"iCloud.com.example.ajohnson.GalleryShared"];
    
    //添加一条记录(这里是添加到公有数据库里面)
    [publicDatabase saveRecord:artworkRecord completionHandler:^(CKRecord *artworkRecord, NSError *error){
        if (!error) {
            //写入成功
        }
        else {
            //写入失败的处理
        }
    }];

注意:

  • 默认用户只能只读数据库,要添加修改则需要登录icloud账户

  • 公有数据库所有的用户(安装app的用户,不是指开发者)都可以访问,私有的只能当前用户能访问.

  • 如果用户没有登录,提醒用户登录icloud


    [[CKContainer defaultContainer] accountStatusWithCompletionHandler:^(CKAccountStatus accountStatus, NSError* error) {
        if (accountStatus == CKAccountStatusNoAccount) {
            UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"尚未登录iCloud" message:nil preferredStyle:UIAlertControllerStyleAlert];

            [alert addAction:[UIAlertAction actionWithTitle:@"确定"
                                                      style:UIAlertActionStyleCancel
                                                    handler:nil]];

            dispatch_async(dispatch_get_main_queue(), ^{
                [self presentViewController:alert animated:YES completion:nil];
            });
        }
        else {
          //登录过了
        }
    }];

获取一条记录

CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"115"];
[publicDatabase fetchRecordWithID:artworkRecordID completionHandler:^(CKRecord *artworkRecord, NSError *error) {
   if (error) {
     //处理错误
   }
   else {
     // 成功获取到数据
   }
}];

修改记录

// 先获取记录
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"115"];
[publicDatabase fetchRecordWithID:artworkRecordID completionHandler:^(CKRecord *artworkRecord, NSError *error) {
   if (error) {
      // 获取失败
   }
   else {
      //修改记录
      NSDate *date = artworkRecord[@"date"];
      artworkRecord[@"date"] = [date dateByAddingTimeInterval:30.0 * 60.0];
      //保存修改后的记录
      [publicDatabase saveRecord:artworkRecord completionHandler:^(CKRecord *savedRecord, NSError *saveError) {
         
      }];
   }
}];

按照条件查询

  • 查询title是 Santa Cruz Mountains 的记录
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title = %@", @"Santa Cruz Mountains"];
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Artwork" predicate:predicate];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
    if (error) {
        //处理错误
    }
    else {
        // 查询成功
    }
}];

  • 查询条件如下:摘自官方文档


    Paste_Image.png

存储大文件(资源文件,如图片)

   //本地文件的URL
   NSURL *resourceURL = [NSURL fileURLWithPath:@"…"];
   if (resourceURL){
      CKAsset *asset = [[CKAsset alloc] initWithFileURL:resourceURL];
      artworkRecord[@"image"] = asset;
     //保存
   }

添加地理位置

CLGeocoder *geocoder = [CLGeocoder new];
[geocoder geocodeAddressString:artwork[kArtworkAddressKey] completionHandler:^(NSArray *placemark, NSError *error){
   if (!error) {
      if (placemark.count > 0){
         CLPlacemark *placement = placemark[0];
         artworkRecord[kArtworkLocationKey] = placement.location;
      }
   }
   else {
     
   }
   // 保存到数据库
}];

根据地理位置查询记录

//公有数据库 
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
 
// 创建一个地理位置
CLLocation *fixedLocation = [[CLLocation alloc] initWithLatitude:37.7749300 longitude:-122.4194200];
//半径,单位是米
CGFloat radius = 100; // meters
//查找距离fixedLocation 不到100米的记录
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"distanceToLocation:fromLocation:(location, %@) < %f", fixedLocation, radius];
 
// 创建一个查询
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Artwork" predicate:predicate];
 
// 执行查询
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
   if (error) {
      //错误处理
   }
   else {
      // 查询成功
   }
}];

添加引用,类似于外键

  • artist 引用了 artistRecordID这条记录

CKRecordID *artistRecordID = [[CKRecordID alloc] initWithRecordName:@"Mei Chen"];

CKReference *artistReference = [[CKReference alloc] initWithRecordID:artistRecordID action:CKReferenceActionNone];

CKRecord *artworkRecord;
…
artworkRecord[@"artist"] = artistReference;

查询引用

  • 查询当前记录的引用
CKRecord *artworkRecord;
…
CKReference *referenceToArtist = artworkRecord[@"artist"];

//拿到引用的id
CKRecordID *artistRecordID = artistReference.recordID;

//根据id查询
[publicDatabase fetchRecordWithID:artistRecordID completionHandler:^(CKRecord *artistRecord, NSError *error) {
    if (error) {
        //错误处理
    }
    else {
        // 查询成功
    }
}];

  • 查询artistRecordID的引用者(可以有很多个引用者)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@“artist = %@”, artistRecordID];

//引用者类型为Artwork
CKQuery *query = [[CKQuery alloc] initWithRecordType:@“Artwork” predicate:predicate];

CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
    if (error) {
        // 错误处理
    }
    else {
        // 查询成功
    }
}];

批处理操作

CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:fetchRecordIDs];

fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
    if (error) {
        
    }
    else {
        
    }
};

fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
    if (error) {
        
    }
    else {
        
    }
};

fetchRecordsOperation.database = [[CKContainer defaultContainer] publicCloudDatabase];
[fetchRecordsOperation start];

订阅 & 推送功能

CKRecordID *artistRecordID = [[CKRecordID alloc] initWithRecordName:@"Mei Chen"];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"artist = %@", artistRecordID];

//创建一个订阅
CKSubscription *subscription = [[CKSubscription alloc]
                                    initWithRecordType:@"Artwork"
                                    predicate:predicate
                                    options:CKSubscriptionOptionsFiresOnRecordCreation];
                                    
CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
notificationInfo.alertLocalizationKey = @"New artwork by your favorite artist.";
notificationInfo.shouldBadge = YES;

subscription.notificationInfo = notificationInfo;

CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
    [publicDatabase saveSubscription:subscription
                    completionHandler:^(CKSubscription *subscription, NSError *error) {
                        if (error)
                            
                    }
     ];

  • 注册通知

      UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
      [application registerUserNotificationSettings:notificationSettings];
      [application registerForRemoteNotifications];
    
    
  • 处理通知

    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    CKNotification *cloudKitNotification = [CKNotification notificationFromRemoteNotificationDictionary:userInfo];
    NSString *alertBody = cloudKitNotification.alertBody;
    if (cloudKitNotification.notificationType == CKNotificationTypeQuery) {
     CKRecordID *recordID = [(CKQueryNotification *)cloudKitNotification recordID];
      }
    }
    
    
  • 然后在后台修改一条记录试试.

别忘了最后一步,部署到线上.

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容