iOS开发 - OC - 苹果为大家提供的后台:CloudKit 的简单使用

一、什么是cloudKit

移动开发中,网络请求数据是日常中用到的,我们习惯把一些用户改动的数据存在服务器,以便下次请求使用。或者开发者方通过服务器将编辑的数据发送给用户。但是这一切都建立在我们的APP拥有自己的服务器之上。如果没有服务器的情况下我们的某些开发就变得很难进行,比如,公司没有服务器,确需要你做出一个用户系统,这显然令人头痛,因为这几乎是一个不可能完成的任务(有人说,扯淡吧,公司会没有服务器? 呵呵,我公司就没有啊)。然而苹果提供了一些便利,虽然不能完全替代后端,但是在一定程度上可以解决数据的云端存储需求,没错就是本文要讲的:CloudKit。每个开发者在使用CloudKit之后,苹果会为其提供一个不小的dashboard作为云端数据的存储地,CloudKit 提供了一套API用于在dashboard中存取数据。简直太方便了啊有米有。

关于CloudKit的详细说明,我建议大家看看这里

二、如何使用cloudKit

使用之前,我们先了解下关于CloudKit的一些基本数据类型。

CloudKit 基础对象类型

CloudKit 的基础对象类型有 7 种。这些对象类型可能和你在其他编程领域了解的类似对象类型稍有差别。

  • CKContainer: Containers 就像应用运行的沙盒一样,一个应用只能访问自己沙盒中的内容而不能访问其他应用的。Containers 就是最外层容器,每个应用有且仅有一个属于自己的 container。(事实上,经过开发者授权配置 CloudKit Dashboard 之后,一个应用也可以访问其他应用的 container。)
  • CKDatabase: Database 即数据库,私有数据库用来存储敏感信息,比如说用户的性别年龄等,用户只能访问自己的私有数据库。应用也有一个公开的数据库来存储公共信息,例如你在构建一个根据地理位置签到的应用,那么地理位置信息就应该存储在公共数据库里以便所有用户都能访问到。
  • CKRecord: 即数据库中的一条数据记录。CloudKit 使用 record 通过 k/v 结构来存储结构化数据。关于键值存储,目前值的架构支持 NSString、NSNumber、NSData、NSDate、CLLocation,和 CKReference、CKAsset,以及存储以上数据类型的数组。
  • CKRecordZone: Record 不是以零散的方式存在于 database 之中的,它们位于 record zones 里。每个应用都有一个 default record zone,你也可以有自定义的 record zone。
  • CKRecordIdentifier: 是一条 record 的唯一标识,用于确定该 record 在数据库中的唯一位置。
  • CKReference: Reference 很像 RDBMS 中的引用关系。还是以地理位置签到应用为例,每个地理位置可以包含很多用户在该位置的签到,那么位置与签到之间就形成了这样一种包含式的从属关系。
  • CKAsset: 即资源文件,例如二进制文件。还是以签到应用为例,用户签到时可能还包含一张照片,那么这张照片就会以 asset 形式存储起来。

本文就一个简单的例子说说使用cloudKit。假如我们需要做一个用户信息的存储系统。

使用CloudKit 的环境配置     

     在使用CloudKit之前,我们需要先在Xcode 中做一些配置。 (本文基于Xcode8)

  1. 在target -> capabilities 中找到 iColod选项。

  2. 打开iCloud的控制开关。
  3. 在展开的框中做如下设置  

其中在containers中的 “ cloudKit dashBoard ”按钮可以直接进入到我们在icloud上的存储空间。 这里要确保APP中使用的开发者账号是实际存在的 。进入网页之后登录开发者账号登录。

登录成功会出现这个画面:

这里我已经存了一部分数据。 存进去之后还是很直观的,但是看不到存储的属性对应的内容,我也还在研究中。

使用CloudHit 保存数据

如果我们需要保存一个包含了用户的  账户、密码、用户名字、电话号码、邮箱、用户头像等数据的对象。 我们创建一个用户的属性类  UserInfoModel。

#import <Foundation/Foundation.h>

@interface UserInfoModel : NSObject

/** 账户名称 */
@property (nonatomic,strong)NSString *userAccout;

/** 用户名字 */
@property (nonatomic,strong) NSString *userName;

/** 用户头像 */
@property (nonatomic,strong) UIImage *userAvtar;

/** 用户手机号码 */
@property (nonatomic,strong) NSString *userPhoneNum;

/** 用户邮箱号 */
@property (nonatomic,strong) NSString *userEmail;

/** 用户密码 */
@property (nonatomic,strong) NSString *userPassword;

@end

在保存数据之前,我们为了之后方便查询,可以将某一项作为唯一标示(这要求标示不会经常被修改),比如在这里我们选择账户名,当然你也可以选择其他任意的字符,关键是之后的查找要有依据。  接下来就开始进行保存了。

 - (void)saveWithModel:(UserInfoModel*)userInfoModel{
    //因为账户名不变的 以帐户名做微ID最好不过了
    CKRecordID *postrecordID = [[CKRecordID alloc]initWithRecordName:userInfoModel.userAccout];
    CKRecord *postRecrod = [[CKRecord alloc] initWithRecordType:userInfoModel.userAccout recordID:postrecordID];

    //将用户类的属性和属性值打包成一个字典  其中属性对应key 属性值对应Value  因为属性中有一栏是图片类,CloudKit不支持直接对图片进行保存,但是可以转换成NSdata,这洋就可以进行保存了.   这里说明一下 cloudKit的提交 只接受NSString、NSNumber、NSData、CLLocation,和 CKReference、CKAsset 等直接的存储, 其它的需要
    NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
    NSMutableArray *propArr = [self getAllProp:[userInfoModel class]];   //这里使用getAllProp 在下面贴出
    for (NSString *prop in propArr) { if([[userInfoModel valueForKey:prop] isKindOfClass:[UIImage class]]){
        // 图片特殊情况另外处理  如果实别的不符合存储的也同样需要处理
        UIImage *image = [userInfoModel valueForKey:prop];

        postRecrod[prop] = [NSData dataWithData:UIImagePNGRepresentation(image)]; //record可以像字典一样进行数据的收纳
    }else{
        postRecrod[prop] = [userInfoModel valueForKey:prop];
    }
    }

    //用户信息 提交到 云
    [[[CKContainer defaultContainer] privateCloudDatabase] saveRecord:postRecrod completionHandler:^(CKRecord *savedPlace, NSError *error) {
        if(savedPlace){
            DLog(@"%@",savedPlace);  //成功  打印存储的内容

        }else{
            DLog(@"%@",error);    //失败 打印错误
        }
    }];

    }
- (NSMutableArray *)getAllProp:(Class)cls{
    // 获取当前类的所有属性
    unsigned int count;// 记录属性个数
    objc_property_t *properties = class_copyPropertyList(cls, &count);
    // 遍历
    NSMutableArray *mArray = [NSMutableArray array];
    for (int i = 0; i < count; i++) {
        // objc_property_t 属性类型
        objc_property_t property = properties[i];
        // 获取属性的名称 C语言字符串
        const char *cName = property_getName(property);
        // 转换为Objective C 字符串
        NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
        [mArray addObject:name];
    }
    return mArray;
} 

使用CloudHit 查询数据

- (void )cloudGetUserInfoWithUseraccout:(NSString *)userAccout Succeed:(void(^)(UserInfoModel* ))succeed failed:(void(^)(NSError *))failed{

    UserInfoModel *model = [[UserInfoModel alloc]init];
    if(userAccout){
        CKRecordID *postrecordID = [[CKRecordID alloc]initWithRecordName:userAccout];
        [[[CKContainer defaultContainer] privateCloudDatabase] fetchRecordWithID:postrecordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {
            // handle errors here
            if(error){
                if(failed){
                    failed(error);
                }
            }else{  //说明查询成功
                if(succeed){

                    //已经获取到了存入的数据, 并经过转换存入了字典 dic  将字典中的键值对赋给一个类对应的属性 同理因为其中有一个图片 所以需要做一个NSdata的转换
                    NSMutableArray *mArray = [self getAllProp:[model class]];
                    for (NSString *prop in mArray) { //这里如果不是在后台人为添加的数据 不会出现没有对应的属性的情况  但是为了保险起见。在UserInfoModel 重写 setVale:forUndefinedKey方法
                        id info = [record valueForKey:prop];
                        if(![info isKindOfClass:[NSData class]]){
                            //                        [model setValue:[dic valueForKey:prop] forKey:prop];
                            [model setValue:record[prop] forKey:prop];

                        }else{
                            UIImage *image = [UIImage imageWithData:info];
                            [model setValue:image forKey:prop];
                        }
                    }
                    succeed(model); //回调获取到的模型
                }
            }
        } ];
    }
}

使用CloudHit 删除数据

- (void)cloudDeleteModelWithModel:(UserInfoModel *)userInfoModel{
    //之前也说了在存储的时候, 我们操纵cloud上的数据都是通过record ID来实现的, 所以record ID的名字应该是一个不经常改变的属性, 这里用的就是用户的账户名
    CKRecordID *postrecordID = [[CKRecordID alloc]initWithRecordName:userInfoModel.userAccout];
    [[[CKContainer defaultContainer] privateCloudDatabase] deleteRecordWithID:postrecordID completionHandler:^(CKRecordID * _Nullable recordID, NSError * _Nullable error) {
        if(!error){
                //删除成功
        }else{
                DLog(@"删除失败%@",error);    //打印错误
        }
    }];
}

以上就是cloudKit的简单使用。通过这个,当需要存储一些比较简单的数据还是可以满足的。

PS:我也刚开始用,发现了一个小问题, 单次存储的数据不能太大(大小没有测试,大概是2M左右吧),不然会提示失败。   所以有的数据过大,可能需要经过拆分,或者图片过大需要经过压缩才能进行存储。

时间: 2024-08-29 11:50:55

iOS开发 - OC - 苹果为大家提供的后台:CloudKit 的简单使用的相关文章

iOS开发OC基础:OC属性的一些概念和基本使用

一.属性简介 //属性是OC2.0之后新出的一种语法,能让我们快速的生成setter以及getter方法,大大简化代码 二.如何定义一个属性 //@property 属性关键字,用来定义属性 //NSString * 属性的类型 //name 属性的名字. //@property 只是生成的setter以及getter方法的声明.@property NSString *name; 三.属性的使用注意事项//如果在.m文件中我们自己实现了setter以及getter方法,则编译器就不会再帮我们生成

iOS开发OC基础:OC基础概念总结,OC面向对象的思想

一.什么是OOP: OOP(Object Oriented Programming):面向对象编程 二.面向对象和面向过程的区别: 面向过程编程:分析解决问题的步骤,实现函数,依次使用面向对象编程:分解问题组成的对象,协调对象间的联系和通信,解决问题. 面向过程是以事件为中心,关心的是完成这个事件的详细步骤:面向对象是以事物为中心,关心的是事物应该具备的功能,而完成一个事件只是事物所有功能里面的一个小功能(以过程为中心,以对象为中心) 三.类和对象 对象定义了解决问题的步骤中的行为,不刻意完成一

iOS开发OC基础:Xcode中常见英文总结,OC常见英文错误

在开发的过程中难免会遇到很多的错误,可是当看到系统给出的英文时,又不知道是什么意思.所以这篇文章总结了Xcode中常见的一些英文单词及词组,可以帮助初学的人快速了解给出的提示.多练习,就肯定能基本掌握. expression:表达式assignable:赋值variable:变量redefinition:重复定义type:类型conflicting:冲突项invalid:无效的conversion:转换specifier:说明符indent:缩进operands:运算对象.操作数binary:二

iOS开发OC基础:OC的内存管理

OC内存管理的基础知识 /** //             *  当对一个对象autorelease时,会将该对象放到离它最近的自动释放池,当自动释放池将要销毁时,会对自动释放池中的对象发送release消息,让对象的引用计数减1,(切记,是将对象的引用计数减1,而不是回收空间.) //             */ /** *  如果相对一个对象做copy操作,就必须让该类服从NSCopying协议,并且实现协议中的- (id)copyWithZone:(NSZone *)zone方法 */

iOS开发OC基础:OC中的分类(类目)

//分类,category,(类目) //为没有源代码的类添加方法 //一定要注意,只能添加方法,不能添加实例变量 /** *  分类 类的定义也是分为接口部分和实现部分 接口部分:以@interface开头 + 类名 后跟小括号,小括号内填写的是分类名 @end结束 在@interface 与@end 之间添加方法. */ //分类为原类添加的方法,就相当于原类具有该方法,可以正常调用 因为涉及到几个分类的创建,所以就直接上传代码了,其实代码也不多,只是怕大家在建立分类的时候会混淆,所以直接把

iOS开发OC基础:延展Extension

//延展Extension,是为类扩充私有的方法,以及私有的实例变量,和分类Category相比,延展定义的方法是私有的,而且还可以定义实例变量(私有的). //@interface 开头 + 类名(哪一个类的延展) + 小括号,小括号内填写的是延展名,一般情况下都省略. @end结束 (写在.m文件里) main函数中的完整代码为: #import <Foundation/Foundation.h> #import "Person.h" int main(int argc

iOS开发OC基础:OC中的协议

1.协议是一种为有源代码的类扩充方法的方式. 2.协议只是一系列方法的生命,就相当于一张任务清单,规定了要做的事情,但是具有的实施(也就是实现),是由服从该协议的类来实现.所以协议只有.h文件,并且不可以定义变量 3.协议的定义是以@protocol开头, + 协议的名字 <>(表示服从的协议)服从的协议写在<>之内,多个协议之间通过逗号来进行分隔,父协议中的内容就相当于子协议也具有这些内容,以@end结束. 下面的附件是协议的一个小例子,可以加深大家对协议的理解,看完之后一定要多

李洪强iOS开发之苹果使用预览截图

李洪强iOS开发之苹果使用预览截图 01 在预览的图片中选中你要截得区域  02 - command + C   03 - Command + N 04 - Command + S (保存)

ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

本文转自 :http://www.cnblogs.com/wendingding/p/3761730.html ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局 一.实现效果 二.使用纯代码自定义一个tableview的步骤 1.新建一个继承自UITableViewCell的类 2.重写initWithStyle:reuseIdentifier:方法 添加所有需要显示的子控件(不需要设置子控件的数据和frame,  子控件要添加到contentView中

iOS开发UI基础—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

ios开发UI基础-使用纯代码自定义UItableviewcell实现一个简单的微博界面布局 一.实现效果 二.使用纯代码自定义一个tableview的步骤 1.新建一个继承自UITableViewCell的类 2.重写initWithStyle:reuseIdentifier:方法 添加所有需要显示的子控件(不需要设置子控件的数据和frame,  子控件要添加到contentView中) 进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片) 3.提供2个模型 数据模型: