iOS开发-iCloud的简单使用(3)-Cloud Kit的使用

好了,看完了key-value,看完了Document的存储,终于到了Cloud kit的使用了。

比起前边的两种,Cloud kit更像是一个数据库。苹果会提供一个dashboard作为云存储的管理端。

Cloud Kit 基础

cloud kit一共有7个基础类,简单了解一下这些基础类接下来的使用就比较容易理解了。

CKContainer

CKContainer类似于应用运行时的沙盒,一个应用只能访问自己的沙盒,同样的,一个应用也只能访问自己的Container。

通过初始化之后就可以使用


 CKContainer *container = [CKContainer defaultContainer];

CKDatabase

CKDatabase很明显就是数据库,他拥有私有数据库公有数据库两种类型。用户只能访问自己的私有数据库,一些不敏感的数据也可以存储在公有数据库中。


 //公有数据库

 CKDatabase *datebase = container.publicCloudDatabase;

 //私有数据库

 CKDatabase *datebase = container.privateCloudDatabase;

CKRecord

CKRecord就是数据库中的一条数据记录,他通过key-value的方式来存储和获取数据。目前可以支持如下格式的数据:

  • NSString(swift中的Sting)

  • NSNumber

  • NSData

  • NSDate

  • CLLocation

  • CKReference

  • CKAsset

其中图片的数据类型需要先初始化一个URL,然后把图片保存到本地沙盒,生成URL,再创建CKAsset来存储。

CKRecordZone

CKRecordZone是用来保存Record的。所有的Record都是保存在这里,应用有一个默认的zone,也可以自定义zone

CKRecordIdentifier

CKRecordIdentifierRecord的唯一标示,用来确定Record在数据库中的位置。

CKReference

CKReference是一种引用关系。

CKAsset

CKAsset 为资源文件,比如之前提到的照片就是用这种方式存储的。

CloudKit Dashboard

更新:

这里还有一个WWDC的视频介绍Cloud dashboard

Build Better Apps with CloudKit Dashboard]

CloudKit Dashboard 的入口在这里:

CloudKitDashboardEnter.png

你也可以直接访问地址

这个界面好像更新过了,和网上很多教程的样式都不太一样。新的界面长这样:

CloudKitDashboardWeb.png

新的界面包括开发版和产品版(线上版)两种,在开发的时候我们就只针对左边的开发版进行操作就可以了。无论是那个版本,都有五个相同的入口。

Data

Cloud kit的数据管理中心入口。在这里可以进行数据的字段,索引等内容设定。

Logs

查看Cloud kit的服务日志,显示数据库操作,推送通知以及对应环境中的其他活动。

Telemetry

查看对应环境中服务器端性能和数据库利用率的图表。

Public Database Usage

查看公共数据库的使用情况图标,包括活跃用户、请求频率等。

Api Access

管理API令牌和服务器密钥,允许对应环境进行web服务调用。

使用

这次我们只讲简单的操作,所以本篇文章就只使用 Data中的部分功能。

创建 RECORD TYPE

首先点击Data , RECORD TYPE , Create New Type创建一个新的RECORD TYPE。

CloudKitCreateRecordType.png

这里注意,我们的RECORD TYPE Name 是Note,这个在之后代码里操作非常重要,所以记得不要写错了。

添加 Field

有了表,接下来就是添加字段了。点击Add Field 然后输入字段名,选择类型就可以了。这里可以一次性添加多条,添加完点击保存就可以了。

CloudKitAddField.png

添加的内容有:

  • title String

  • content String

  • photo Asset

添加 indexs

为了搜索更方便一些,我们添加一些索引。

点击INDEXS,选择我们刚刚添加的Note,然后添加索引,添加的索引类型有QUERYABLE,SEARCHABLE,SORTABLE

CloudKitAddIndex.png

添加的内容有:

  • title QUERYABLE

  • title SEARCHABLE

  • title SORTABLE

  • content QUERYABLE

  • content SEARCHABLE

  • content SORTABLE

  • recordName QUERYABLE

添加完就是这样的,对照一下看看有没有添加错啊。

CloudKitAddIndexFinished.png

添加数据

接下来,我们就可以给表里添加数据了。

选择RECORD ,确认LOAD RECORDS FROMQUERY FOR RECORDS OF TYPE 都正确了之后,点击Creat New Record...,在右边输入想要插入的数据,添加个几条就可以了。

CloudKitAddRecord.png

查询数据

随便添加几条数据之后,还是在这个页面,点击左侧的Query Records,就可以查询到数据了。

CloudKitQueryRecords.png

到此,Cloud Dashboard的简单使用就介绍到这,接下来我们看看通过代码怎么来操作Cloud kit。

撸起袖子写代码吧。

通过代码操作 Cloud Kit

使用Cloud Kit时,首先要先引入Cloud kit的框架。


#import <CloudKit/CloudKit.h>

添加数据

首先创建一个容器


 //获取容器

 CKContainer *container = [CKContainer defaultContainer];

然后获取数据库,这里我们使用公有数据库


 //公共数据

 CKDatabase *datebase = container.publicCloudDatabase;

接下来创建一条数据,这里的RECORD_TYPE_NAME就是之前创建表的名字Note


 //创建保存数据

 CKRecord *noteRecord = [[CKRecord alloc] initWithRecordType:RECORD_TYPE_NAME];

添加数据是使用Key-value的方式。


 [noteRecord setValue:title forKey:@"title"];

 [noteRecord setValue:content forKey:@"content"];

这里要特殊注意的是图片的处理,我们先要创建一个URL,然后把图片数据保存到沙盒中,生成一个URL,再创建CKAsset。


 NSDate *dateID = [NSDate dateWithTimeIntervalSinceNow:0];

 NSTimeInterval timeInterval = [dateID timeIntervalSince1970] * 1000; //*1000表示到毫秒级,这样可以保证不会同时生成两个同样的id

 NSString *idString = [NSString stringWithFormat:@"%.0f", timeInterval];

 NSString *filePath = [NSString stringWithFormat:@"%@/%@",tempPath,idString];

 NSURL *url = [NSURL fileURLWithPath:filePath];

 [imageData writeToURL:url atomically:YES];

 CKAsset *asset = [[CKAsset alloc]initWithFileURL:url];

 [noteRecord setValue:asset forKey:@"photo"];

对了,还有CKAsset转UIImage的方法:


CKAsset *asset = [record objectForKey:@"photo"];

UIImage *image = [UIImage imageWithContentsOfFile:asset.fileURL.path];

这样数据的内容就处理好了,接下来我们只要把它保存起来就可以咯。


 [datebase saveRecord:noteRecord completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {

 if(!error)

 {

 NSLog(@"保存成功");

 }

 else

 {

 NSLog(@"保存失败");

 NSLog(@"%@",error.description);

 }

 }];

整个代码合起来就是这样的:


+ (void)saveCloudKitModelWithTitle:(NSString *)title content:(NSString *)content photoImage:(UIImage *)image

{

 //获取容器

 CKContainer *container = [CKContainer defaultContainer];

 //公共数据

 CKDatabase *datebase = container.publicCloudDatabase;

// //私有数据

// CKDatabase *datebase = container.privateCloudDatabase;

// //创建主键

// CKRecordID *noteID = [[CKRecordID alloc] initWithRecordName:@"NoteID"];

 //创建保存数据

 CKRecord *noteRecord = [[CKRecord alloc] initWithRecordType:RECORD_TYPE_NAME];

 NSData *imageData = UIImagePNGRepresentation(image);

 if (imageData == nil)

 {

 imageData = UIImageJPEGRepresentation(image, 0.6);

 }

 NSString *tempPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/imagesTemp"];

 NSFileManager *manager = [NSFileManager defaultManager];

 if (![manager fileExistsAtPath:tempPath]) {

 [manager createDirectoryAtPath:tempPath withIntermediateDirectories:YES attributes:nil error:nil];

 }

 NSDate *dateID = [NSDate dateWithTimeIntervalSinceNow:0];

 NSTimeInterval timeInterval = [dateID timeIntervalSince1970] * 1000; //*1000表示到毫秒级,这样可以保证不会同时生成两个同样的id

 NSString *idString = [NSString stringWithFormat:@"%.0f", timeInterval];

 NSString *filePath = [NSString stringWithFormat:@"%@/%@",tempPath,idString];

 NSURL *url = [NSURL fileURLWithPath:filePath];

 [imageData writeToURL:url atomically:YES];

 CKAsset *asset = [[CKAsset alloc]initWithFileURL:url];

 [noteRecord setValue:title forKey:@"title"];

 [noteRecord setValue:content forKey:@"content"];

 [noteRecord setValue:asset forKey:@"photo"];

 [datebase saveRecord:noteRecord completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {

 if(!error)

 {

 NSLog(@"保存成功");

 }

 else

 {

 NSLog(@"保存失败");

 NSLog(@"%@",error.description);

 }

 }];

}

查询数据

查询所有数据

查询数据同样,我们也要先获取容器和数据库。


 //获取位置

 CKContainer *container = [CKContainer defaultContainer];

 CKDatabase *database = container.publicCloudDatabase;

之后我们添加一个查询的条件,cloud kit和core data一样,都是使用NSPredicate

而且还要用到CKQuery这个类。


 //添加查询条件

 NSPredicate *predicate = [NSPredicate predicateWithValue:YES];

 CKQuery *query = [[CKQuery alloc] initWithRecordType:RECORD_TYPE_NAME predicate:predicate];

准备好了,接下来就可以调用查询方法了,获取到的results就是获取到数据的数组了,这里我用了通知的方法把查询到的数据传出去。


 //开始查询

 [database performQuery:query inZoneWithID:nil completionHandler:^(NSArray<CKRecord *> * _Nullable results, NSError * _Nullable error) {

 NSLog(@"%@",results);

 //把数据做成字典通知出去

 NSDictionary *userinfoDic = [NSDictionary dictionaryWithObject:results forKey:@"key"];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"CloudDataQueryFinished" object:nil userInfo:userinfoDic];

 }];

整个代码合起来就是这样的:


//查询数据

+ (void)queryCloudKitData

{

 //获取位置

 CKContainer *container = [CKContainer defaultContainer];

 CKDatabase *database = container.publicCloudDatabase;

 //添加查询条件

 NSPredicate *predicate = [NSPredicate predicateWithValue:YES];

 CKQuery *query = [[CKQuery alloc] initWithRecordType:RECORD_TYPE_NAME predicate:predicate];

 //开始查询

 [database performQuery:query inZoneWithID:nil completionHandler:^(NSArray<CKRecord *> * _Nullable results, NSError * _Nullable error) {

 NSLog(@"%@",results);

 //把数据做成字典通知出去

 NSDictionary *userinfoDic = [NSDictionary dictionaryWithObject:results forKey:@"key"];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"CloudDataQueryFinished" object:nil userInfo:userinfoDic];

 }];

}

查询单个数据

同样也是获取容器和数据库。


 //获取位置

 CKContainer *container = [CKContainer defaultContainer];

 CKDatabase *database = container.publicCloudDatabase;

然后我们需要获取查询的数据的RecordID。


 [database fetchRecordWithID:recordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {

 dispatch_async(dispatch_get_main_queue(), ^{

 NSLog(@"%@",record);

 //把数据做成字典通知出去

 NSDictionary *userinfoDic = [NSDictionary dictionaryWithObject:record forKey:@"key"];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"CloudDataSingleQueryFinished" object:nil userInfo:userinfoDic];

 });

 }];

合起来代码就是这样的:


//查询单条数据

+ (void)querySingleRecordWithRecordID:(CKRecordID *)recordID

{

 //获取容器

 CKContainer *container = [CKContainer defaultContainer];

 //获取公有数据库

 CKDatabase *database = container.publicCloudDatabase;

 [database fetchRecordWithID:recordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {

 dispatch_async(dispatch_get_main_queue(), ^{

 NSLog(@"%@",record);

 //把数据做成字典通知出去

 NSDictionary *userinfoDic = [NSDictionary dictionaryWithObject:record forKey:@"key"];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"CloudDataSingleQueryFinished" object:nil userInfo:userinfoDic];

 });

 }];

}

删除数据

删除数据同样,我们也要先获取容器和数据库。


 //获取位置

 CKContainer *container = [CKContainer defaultContainer];

 CKDatabase *database = container.publicCloudDatabase;

然后,在删除数据时,要获取到你要删除的数据的RecordID,之后直接执行删除方法即可


 [database deleteRecordWithID:recordID completionHandler:^(CKRecordID * _Nullable recordID, NSError * _Nullable error) {

 if(error)

 {

 NSLog(@"删除失败");

 }

 else

 {

 NSLog(@"删除成功");

 }

 }];

合起来代码就是这样


//删除数据

+ (void)removeCloudKitDataWithRecordID:(CKRecordID *)recordID

{

 CKContainer *container = [CKContainer defaultContainer];

 CKDatabase *database = container.publicCloudDatabase;

 [database deleteRecordWithID:recordID completionHandler:^(CKRecordID * _Nullable recordID, NSError * _Nullable error) {

 if(error)

 {

 NSLog(@"删除失败");

 }

 else

 {

 NSLog(@"删除成功");

 }

 }];

}

修改数据

还是那句话,先获取容器


 CKContainer *container = [CKContainer defaultContainer];

 CKDatabase *database = container.publicCloudDatabase;

其实修改数据就是重新把数据写入。在写入的时候如果选择之前没有的key,就相当于新增了一个字段。然后执行保存操作就可以了。

直接上全部的代码好了:


//修改数据

+ (void)changeCloudKitWithTitle:(NSString *)title content:(NSString *)content photoImage:(UIImage *)image RecordID:(CKRecordID *)recordID

{

 //获取容器

 CKContainer *container = [CKContainer defaultContainer];

 //获取公有数据库

 CKDatabase *database = container.publicCloudDatabase;

 [database fetchRecordWithID:recordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {

 NSData *imageData = UIImagePNGRepresentation(image);

 if (imageData == nil)

 {

 imageData = UIImageJPEGRepresentation(image, 0.6);

 }

 NSString *tempPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/imagesTemp"];

 NSFileManager *manager = [NSFileManager defaultManager];

 if (![manager fileExistsAtPath:tempPath]) {

 [manager createDirectoryAtPath:tempPath withIntermediateDirectories:YES attributes:nil error:nil];

 }

 NSDate *dateID = [NSDate dateWithTimeIntervalSinceNow:0];

 NSTimeInterval timeInterval = [dateID timeIntervalSince1970] * 1000; //*1000表示到毫秒级,这样可以保证不会同时生成两个同样的id

 NSString *idString = [NSString stringWithFormat:@"%.0f", timeInterval];

 NSString *filePath = [NSString stringWithFormat:@"%@/%@",tempPath,idString];

 NSURL *url = [NSURL fileURLWithPath:filePath];

 [imageData writeToURL:url atomically:YES];

 CKAsset *asset = [[CKAsset alloc]initWithFileURL:url];

 [record setObject:title forKey:@"title"];

 [record setObject:content forKey:@"content"];

 [record setValue:asset forKey:@"photo"];

 [database saveRecord:record completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {

 if(error)

 {

 NSLog(@"修改失败 %@",error.description);

 }

 else

 {

 NSLog(@"修改成功");

 }

 }];

 }];

}

Demo

先放一下demo的地址

demo简单的制作了一个简单的cloud kit存储功能,一些交互没有完善,但是基本的增删改查功能都已经实现了。

CloudKitDemo.gif

以上就是Cloud Kit的简单使用。此文章仅供个人学习使用,如有不当,希望大佬指出。

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

推荐阅读更多精彩内容