CloudKit是苹果推出的基于iCloud的一个云端数据存储服务.其 主要由下面两部分组成:git
一个仪表web页面,用于管理公开数据的记录类型.github
一组API接口,用于iCloud和设备之间的数据传递.web
一:首先在XCode上面打开关于iCloud功能数据库
1:进入对应的项目Targets 中的Capabilities 选项卡,打开关于iCloud功能;若是勾选iCloud Documents或CloudKit会自动生成一个带iCloud.开头的Containers,要配置证书支持;CloudKit Dashboard则能够直接跳转到Web配置关于iCloud的内容;而关于Steps则是配置的步骤是否都成功;微信
二:关于证书如何配置支持iCloud功能app
1:进入苹果证书管理后台中的Identifiers里有个iCloud Containers菜单框架
由于实例中的Bundle Identifier的名字wjy.com.MobileProject;因此在这边建立一个iCloud.wjy.com.MobileProject的ID值;都是前面增长一个iCloud为开头;app的bundle id须要与iCloud容器相对应, iCloud容器名必须是惟一的,由于这是Cloudkit用来访问数据所使用的全局标识符。因为iCloud容器名包含bundle id,所以bundle id也必须是惟一的(这就是为什么须要修改com.raywendrelich.BabiFud)。 fetch
为了让entitlements起做用,须要在App的证书、标识符与配置文件中ID的部分列出app/bundle id。这意味着标识的证书使用了设置的team id与app id,从中可获得iCloud容器的id。若已经在一个可用的开发者帐号中标识了的话Xcode会自动完成这一切。不巧的是,这有时是不一样步的,须要更新ID-使用iCloud功能面板修改CloudKit容器ID。不然的话须要修改info.plist文件或BabiFud.entitlements文件来确保id values与所设置的bundle id一致。ui
2:建立完上面的ID后,一样进行Identifiers里的App IDs,找到咱们当前的App ID而后对它进行编辑atom
打开iCloud的功能选择,而且选择Include CloudKit support,这边这时会有一个警告出现,选择右边的Edit进行编辑
这时会有刚才建立好的那个iCloud ID能够选择绑定;选择好之后外面的警告也会消除;而后生成对应的描述文件安装后,XCode上面的步骤报错也会消除;
三:设置iCloud的数据
1:要进入CloudKit Dashboard操做有两种方式,第一种如上面第一点所说能够直接点CloudKit Dashboard进入,另外一种就是进入苹果帐号后台也有一个相应的菜单;
2:进入CloudKit Dashboard能够看到以下的页面
2.1 SCHEMA :
CloudKit容器的高级类:Record Types, Security Roles, 和Subscription Types,其中主要使用的是Record Types;
一个Record Type用来定义一个单独的记录(能够理解为一个数据模型),至关于存储数据的模板,和数据库的表结构相似;
2.2 PUBLIC DATA 和 PRIVATE DATA
就是你保存数据的地方,开发者能够查看全部的共享数据,可是只能看到本身的私密数据,没法看到用户的私密数据;这里没有显示PRIBATE DATA,其结构和PUBLIC DATA是同样的;
User Records 记录一些当前使用者的信息;
Default Zone :这里能够查看数据的详细信息,也是后面主要使用的;
2.3 ADMIN 主要是管理开发者团队权限的,这里不作过多介绍;
3:切回Record Type选项,点击右边栏的左上角的 "+ ",新增一个模型:
输入模型名称: 默认只有一个StringField的属性(这里暂且这么称呼吧),能够点击下面的Add Field... 新增属性列表;
一样能够选择属性的类型,以下图:
设置完成后,点击右下角的 Save按钮便可保存!这样,一个模型就创建好了;存储类型的数据:
1. NSData (single bytes) 2. NSDate (date and time) 3. NSNumber (both Int and Double) 4. NSString (or String in Swift) 5. NSArray (list) 6. CKReference (used to create relationships between objects) 7. CLLocation (location) 8. CKAsset (file)
5:回到Default Zone,中间蓝色区域的右上角的名称旁有个倒三角,这里能够选择使用(查询)哪一个模型下的数据:
6:若是要存是图片字段记得选Asset类型
注意:1 Public Record ,1 Private Record,意思是:使用模型Note的有一条公共数据,一条隐私数据,因为我登录的iCloud帐号和开发者帐号不同,至关因而用户帐号,因此这里是看不到那个隐私数据的
四:代码操做iCloud功能
1:首先引入CloudKit.framework系统框架,并引入命名空间#import <CloudKit/CloudKit.h> 就能够进行操做
2:首先是判断手机中的iCloud功能是否开启,以下面若是有值则表示已经开启的iCloud功能;
id cloudUrl=[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
这个方法接受一个参数, 就是要获取的容器标识。 所谓容器标识, 大多数应用只会用到一个 iCloud 容器,因此咱们这里传入 nil, 就表明默认获取第一个可用的容器。这个方法内部会查找当前应用拥有的 iCloud 容器, 若是找到就会返回这个容器的 URL, 证实当前应用的 iCloud 容器可用。 若是找不到,就会返回 nil, 证实当前应用的 iCloud 不可用。
注意: iCloud 容器和你 App 文件沙盒, 在 iOS 文件系统中实际上是分别存放在两个不一样的地方的:
iCloud 文件路径格式 file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~xxx~aaa/Documents
App 沙盒文件路径格式 file:///var/mobile/Containers/Data/Application/3B4376B3-89B5-3342-8057-3450D4224518/Documents/
因而可知, 这也是为何 iCloud 和 Sandbox 文件路径访问须要两套不一样的方式的缘由了。
3:增长一条记录,能够给它一个固定的recordID,就像数据表的主键同样,查找、更新跟删除有用;
-(void)addCloudDataWithPublic:(BOOL)isPublic recordID:(NSString *)recordID name:(NSString *)name password:(NSString *)password { //CloudKit给应用程序分配部分空间,用于存储数据,首先要获取这个存储空间,这里咱们直接获取了默认的存储器(能够自定义存储器): CKContainer *container=[CKContainer defaultContainer]; CKDatabase *database; if (isPublic) { database=container.publicCloudDatabase; //公共数据 } else { database=container.privateCloudDatabase;//隐藏数据 } //建立主键ID 这个ID能够到时查找有用到 CKRecordID *noteId=[[CKRecordID alloc]initWithRecordName:recordID]; //建立CKRecord 保存数据 CKRecord *noteRecord = [[CKRecord alloc]initWithRecordType:@"User" recordID:noteId]; //设置数据 [noteRecord setObject:name forKey:@"name"]; [noteRecord setObject:password forKey:@"password"]; //保存操做 [database saveRecord:noteRecord completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { if (!error) { [self showAlertMessage:@"保存成功"]; } }]; }
4:假如要保存带有图片的字段,须要用到CKAsset,他的初始化须要一个URL,因此这里,我先把图片数据保存到本地沙盒,生成一个URL,而后再去建立CKAsset:
//增长带图片的提交 图片的保存,须要用到CKAsset,他的初始化须要一个URL,因此这里,我先把图片数据保存到本地沙盒,生成一个URL,而后再去建立CKAsset: -(void)saveImageDataWithPublic:(BOOL)isPublic recordID:(NSString *)recordID name:(NSString *)name password:(NSString *)password { //保存图片 图片的保存,须要用到CKAsset,他的初始化须要一个URL,因此这里,我先把图片数据保存到本地沙盒,生成一个URL,而后再去建立CKAsset: UIImage *image=[UIImage imageNamed:@"icloudImage"]; 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]; } NSString *filePath = [NSString stringWithFormat:@"%@/%@",tempPath,@"iCloudImage"]; NSURL *url = [NSURL fileURLWithPath:filePath]; [imageData writeToURL:url atomically:YES]; CKAsset *asset = [[CKAsset alloc]initWithFileURL:url]; //与iCloud进行交互 CKContainer *container=[CKContainer defaultContainer]; CKDatabase *database; if (isPublic) { database=container.publicCloudDatabase; //公共数据 } else { database=container.privateCloudDatabase;//隐藏数据 } //建立主键ID 这个ID能够到时查找有用到 CKRecordID *noteId=[[CKRecordID alloc]initWithRecordName:recordID]; //建立CKRecord 保存数据 CKRecord *noteRecord = [[CKRecord alloc]initWithRecordType:@"User" recordID:noteId]; //设置数据 [noteRecord setObject:name forKey:@"name"]; [noteRecord setObject:password forKey:@"password"]; [noteRecord setObject:asset forKey:@"userImage"]; //保存操做 [database saveRecord:noteRecord completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { if (!error) { [self showAlertMessage:@"保存成功"]; } }]; }
5:查找单条记录的功能,经过recordID进行
//查找单条记录 -(void)searchRecordWithRecordID:(NSString *)recordID withFormPublic:(BOOL)isPublic { //得到指定的ID CKRecordID *noteId=[[CKRecordID alloc]initWithRecordName:recordID]; //得到容器 CKContainer *container=[CKContainer defaultContainer]; //得到数据的类型 是公有仍是私有 CKDatabase *database; if (isPublic) { database=container.publicCloudDatabase; } else { database=container.privateCloudDatabase; } __weak typeof(self)weakSelf = self; //查找操做 [database fetchRecordWithID:noteId completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { NSString *message=[NSString stringWithFormat:@"得到RecordID为%@ 的数据:%@,%@",recordID,[record objectForKey:@"name"],[record objectForKey:@"password"]]; [weakSelf showAlertMessage:message]; }]; }
6:查询多条记录的功能,用到的谓词进行
//查找多条记录(能够用谓词进行) -(void)searchRecordWithFormPublic:(BOOL)isPublic withRecordTypeName:(NSString *)recordTypeName { CKContainer *container=[CKContainer defaultContainer]; //得到数据的类型 是公有仍是私有 CKDatabase *database; if (isPublic) { database=container.publicCloudDatabase; } else { database=container.privateCloudDatabase; } NSPredicate *predicate=[NSPredicate predicateWithValue:YES]; CKQuery *query=[[CKQuery alloc]initWithRecordType:recordTypeName predicate:predicate]; __weak typeof(self)weakSelf = self; [database performQuery:query inZoneWithID:nil completionHandler:^(NSArray<CKRecord *> * _Nullable results, NSError * _Nullable error) { [weakSelf showAlertMessage:[NSString stringWithFormat:@"%@",results]]; }]; }
7:更新一条记录首先要查找出该条记录,再对它进行修改,若是对应的键值存在进修改其值,若是键值不存在则增长新的类型字段;
//更新一条记录 首先要查找出这一条 而后再对它进行修改 -(void)updateRecordWithFormPublic:(BOOL)isPublic withRecordTypeName:(NSString *)recordTypeName withRecordID:(NSString *)recordID { //得到指定的ID CKRecordID *noteId=[[CKRecordID alloc]initWithRecordName:recordID]; //得到容器 CKContainer *container=[CKContainer defaultContainer]; //得到数据的类型 是公有仍是私有 CKDatabase *database; if (isPublic) { database=container.publicCloudDatabase; } else { database=container.privateCloudDatabase; } __weak typeof(self)weakSelf = self; //查找操做 [database fetchRecordWithID:noteId completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { if (!error) { //对原有的健值进行修改 [record setObject:@"aa123456789" forKey:@"password"]; //若是健值不存在 则会增长一个 [record setObject:@"男" forKey:@"gender"]; [database saveRecord:record completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { if (!error) { [weakSelf showAlertMessage:@"修改保存成功"]; } else { [weakSelf showAlertMessage:[NSString stringWithFormat:@"出错误 :%@",error]]; } }]; } }]; }
8:删除一条记录
//删除记录 -(void)deleteRecordWithFormPublic:(BOOL)isPublic withRecordID:(NSString *)recordID { //得到指定的ID CKRecordID *noteId=[[CKRecordID alloc]initWithRecordName:recordID]; //得到容器 CKContainer *container=[CKContainer defaultContainer]; //得到数据的类型 是公有仍是私有 CKDatabase *database; if (isPublic) { database=container.publicCloudDatabase; } else { database=container.privateCloudDatabase; } __weak typeof(self)weakSelf = self; [database deleteRecordWithID:noteId completionHandler:^(CKRecordID * _Nullable recordID, NSError * _Nullable error) { if (!error) { [weakSelf showAlertMessage:@"删除成功"]; return; } [weakSelf showAlertMessage:[NSString stringWithFormat:@"删除失败 %@",error]]; }]; }
五:操做实例
编写一个关于在同一台手机上免登陆的实例,主要原理是经过获取手机设备惟一码,而后经过iCloud保存到云端,在删除APP后再安装后就能够直接从云端得到用户跟密码;会不断完善此实例,若是感兴趣能够点星并关注,会接着编写关于iCloud关于文件的同步功能;注意证书能够换成自个的,步骤如上:
源代码地址:https://github.com/wujunyang/iCloudProject
最近有个妹子弄的一个关于扩大眼界跟内含的订阅号,天天都会更新一些深度内容,在这里若是你感兴趣也能够关注一下(嘿对美女跟知识感兴趣),固然能够关注后输入:github 会有个人微信号,若是有问题你也能够在那找到我;固然不感兴趣无视此信息;