一、iCloud云服务

iCloud是苹果提供的云端服务,用户可以将通讯录、备忘录、邮件、照片、音乐、视频等备份到云服务器并在各个苹果设备间直接进行共享而无需关心数据同步问题,甚至即使你的设备丢失后在一台新的设备上也可以通过Apple ID登录同步。

苹果已经将云端存储功能开放给开发者,可以存储两类数据:
  1. key-value data
    分享小量的非关键配置数据到应用的多个实例,使用类似于NSUserDefault
  2. document
    存储用户文档和应用数据到用户的iCloud账户
进行iCloud开发的准备工作:
  1. 在开发者中心上创建AppleID,启用iCloud服务
  2. 生成对应的配置文件(Provisioning Profile),这里可以使用通配Bundle ID
  3. 以上2步是针对真机的,调试模拟器可以忽略
  4. 打开项目的Capabilities,找到iCloud服务并开启它
  5. 在iCloud服务的Service中勾选Key-value storaeiCloud Documents
  6. 你的项目中就会多出一个entitlements文件
  7. 里面的内容是自动生成的,就像这样的
  8. 无论真机还是模拟器,都需要进入手机的设置中登陆iCloud账号

二、Key-Value的iCloud存储

使用和NSUserDefault差不多,都是以键值对的形式存储。

使用实例:
#import "iCloudKeysViewController.h"

@interface iCloudKeysViewController()
@property (strong, nonatomic) NSUbiquitousKeyValueStore *keyStore;
@property (strong, nonatomic) IBOutlet UILabel *textLabel;
@end @implementation iCloudKeysViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.textLabel.text = @"Ready Go";
//获取iCloud配置首选项
self.keyStore = [NSUbiquitousKeyValueStore defaultStore];
//注册通知中心,当配置发生改变的时候,发生通知
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(ubiquitousKeyValueStoreDidChange:)
name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
object:keyStore];
}
/* UI点击,点击改变按钮 */
- (IBAction)changeKey
{
[self.keyStore setString:@"Hello World" forKey:@"MyString"];
[self.keyStore synchronize];
NSLog(@"Save key");
}
/* 监听通知,当配置发生改变的时候会调用 */
- (void)ubiquitousKeyValueStoreDidChange:(NSNotification *)notification
{
NSLog(@"External Change detected");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Change detected"
message:@"Change detected"
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil, nil];
[alert show];
//显示改变的信息
textLabel.text = [keyStore stringForKey:@"MyString"];
}
@end

三、Document的iCloud存储

核心类UIDocument
  • 文档存储主要是使用UIDocument类来完成,这个类提供了新建、修改、查询文档、打开文档、删除文档的功能。
  • UIDocument对文档的新增、修改、删除、读取全部基于一个云端URL来完成,对于开发者而言没有本地和云端之分,这样大大简化了开发过程。
云端URL的获取方式:
  • 调用NSFileManager的对象方法

    -(NSURL *)URLForUbiquityContainerIdentifier:(NSString *)identifier;
  • 上面需要传递一个云端存储容器的唯一标示,这个可以去自动生成的entitlements文件查看Ubiquity Container Identifiers字段获得,如果传nil,代表第一个容器

补充知识 :

默认的第一个容器标识是iCloud.$(CFBundleIdentifier)
其中$(CFBundleIdentifier)代表Bundle ID,那么根据应用的Bundle ID就可以得知我的第一个容器的标识是iCloud.com.liuting.icloud.iCloudTest

UIDocument的对象方法:
/* 将指定URL的文档保存到iCloud(可以是新增或者覆盖,通过saveOperation参数设定)*/
- (void)saveToURL:(NSURL *)url
forSaveOperation:(UIDocumentSaveOperation)saveOperation
completionHandler:(void (^)(BOOL success))completionHandler;
/* 保存操作option */
typedef NS_ENUM(NSInteger, UIDocumentSaveOperation) {
UIDocumentSaveForCreating,/* 创建 */
UIDocumentSaveForOverwriting/* 覆盖写入 */
};
/* 打开文档,参数是打开文档成功回调 */
- (void)openWithCompletionHandler:(void (^)(BOOL success))completionHandler;
删除文档使用的是NSFileManager的对象方法:
/* 删除指定URL下的文件 */
- (BOOL)removeItemAtURL:(NSURL *)URL
error:(NSError **)error;
注意事项:
  • UIDocument在设计的时候,没有提供统一的存储方式来存储数据,需要我们去继承它,重写2个对象方法自己操作数据

    /*
    保存文档时调用
    @param typeName 文档文件类型
    @param outError 错误信息输出
    @return 文档数据
    */
    -(id)contentsForType:(NSString *)typeName
    error:(NSError **)outError;
    /*
    读取数据时调用
    @param contents 文档数据
    @param typeName 文档文件类型
    @param outError 错误信息输出
    @return 读取是否成功
    */
    -(BOOL)loadFromContents:(id)contents
    ofType:(NSString *)typeName
    error:(NSError **)outError;
  • UIDocument保存数据的本质:
    将A对应类型的数据转化为云端存储的NSData或者NSFileWrapper数据
  • UIDocument读取数据的本质:
    将云端下载的NSData或者NSFileWrapper数据转化为A对应类型的数据

下面是我自定义的Document类,继承于UIDocument:
LTDocument.h文件
#import <UIKit/UIKit.h>
@interface LTDocument : UIDocument
@property (strong, nonatomic) NSData *data;/*< 文档数据 */
@end
LTDocument.m文件
#import "LTDocument.h"
@implementation LTDocument
#pragma mark - 重写父类方法
/**
* 保存时调用
* @param typeName 文档文件类型后缀
* @param outError 错误信息输出
* @return 文档数据
*/
- (id)contentsForType:(NSString *)typeName
error:(NSError *__autoreleasing *)outError
{
if (!self.data) {
self.data = [NSData data];
}
return self.data;
}
/**
* 读取数据时调用
* @param contents 文档数据
* @param typeName 文档文件类型后缀
* @param outError 错误信息输出
* @return 读取是否成功
*/
- (BOOL)loadFromContents:(id)contents
ofType:(NSString *)typeName
error:(NSError *__autoreleasing *)outError
{
self.data = [contents copy];
return true;
}
@end
  • 如果要加载iCloud中的文档列表,就需要使用另一个类NSMetadataQuery
  • 通常考虑到网络的原因并不会一次性加载所有数据,而利用NSMetadataQuery并指定searchScopesNSMetadataQueryUbiquitousDocumentScope来限制查找iCloud文档数据。
  • 使用NSMetadataQuery还可以通过谓词限制搜索关键字等信息,并在搜索完成之后通过通知的形式通知客户端搜索的情况。
下面是使用示例:
1. 属性定义和宏定义:
#import "ViewController.h"
#import "LTDocument.h" #define kContainerIdentifier @"iCloud.com.liuting.icloud.iCloudTest" @interface ViewController () <UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITextField *documentField;/*< 输入框 */
@property (weak, nonatomic) IBOutlet UILabel *documentShowLable;/*< 显示栏 */
@property (weak, nonatomic) IBOutlet UITableView *documentTableView;/* 文档列表 */
/* 文档文件信息,键为文件名,值为创建日期 */
@property (strong, nonatomic) NSMutableDictionary *files;
@property (strong, nonatomic) NSMetadataQuery *query;/*< 查询文档对象 */
@property (strong, nonatomic) LTDocument *document;/*< 当前选中文档 */ @end
2. 获取云端URL方法:
/**
* 取得云端存储文件的地址
* @param fileName 文件名,如果文件名为nil,则重新创建一个URL
* @return 文件地址
*/
- (NSURL *)getUbiquityFileURL:(NSString *)fileName{
//取得云端URL基地址(参数中传入nil则会默认获取第一个容器),需要一个容器标示
NSFileManager *manager = [NSFileManager defaultManager];
NSURL *url = [manager URLForUbiquityContainerIdentifier:kContainerIdentifier];
//取得Documents目录
url = [url URLByAppendingPathComponent:@"Documents"];
//取得最终地址
url = [url URLByAppendingPathComponent:fileName];
return url;
}
3. 查询文档列表方法
/* 从iCloud上加载所有文档信息 */
- (void)loadDocuments
{
if (!self.query) {
self.query = [[NSMetadataQuery alloc] init];
self.query.searchScopes = @[NSMetadataQueryUbiquitousDocumentsScope];
//注意查询状态是通过通知的形式告诉监听对象的
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(metadataQueryFinish:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];//数据获取完成通知
[center addObserver:self
selector:@selector(metadataQueryFinish:)
name:NSMetadataQueryDidUpdateNotification
object:self.query];//查询更新通知
}
//开始查询
[self.query startQuery];
}
/* 查询更新或者数据获取完成的通知调用 */
- (void)metadataQueryFinish:(NSNotification *)notification
{
NSLog(@"数据获取成功!");
NSArray *items = self.query.results;//查询结果集
self.files = [NSMutableDictionary dictionary];
//变量结果集,存储文件名称、创建日期
[items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSMetadataItem *item = obj;
//获取文件名
NSString *fileName = [item valueForAttribute:NSMetadataItemFSNameKey];
//获取文件创建日期
NSDate *date = [item valueForAttribute:NSMetadataItemFSContentChangeDateKey];
NSDateFormatter *dateformate = [[NSDateFormatter alloc]init];
dateformate.dateFormat = @"YY-MM-dd HH:mm";
NSString *dateString = [dateformate stringFromDate:date];
//保存文件名和文件创建日期
[self.files setObject:dateString forKey:fileName];
}];
//表格刷新
self.documentShowLable.text = @"";
[self.documentTableView reloadData];
}
4. UI点击事件
#pragma mark - UI点击事件
/* 点击添加文档 */
- (IBAction)addDocument:(id)sender {
//提示信息
if (self.documentField.text.length <= 0) {
NSLog(@"请输入要创建的文档名");
self.documentField.placeholder = @"请输入要创建的文档名";
return;
}
//创建文档URL
NSString *text = self.documentField.text;
NSString *fileName = [NSString stringWithFormat:@"%@.txt",text];
NSURL *url = [self getUbiquityFileURL:fileName]; //创建云端文档对象
LTDocument *document = [[LTDocument alloc] initWithFileURL:url];
//设置文档内容
NSString *dataString = @"hallo World";
document.data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
//保存或创建文档,UIDocumentSaveForCreating是创建文档
[document saveToURL:url
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success)
{
if (success) {
NSLog(@"创建文档成功.");
self.documentField.text = @"";
//从iCloud上加载所有文档信息
[self loadDocuments];
}else{
NSLog(@"创建文档失败.");
} }];
}
/* 点击修改文档 */
- (IBAction)saveDocument:(UIButton *)sender {
if ([sender.titleLabel.text isEqualToString:@"修改文档"]) {
self.documentField.text = self.documentShowLable.text;
[sender setTitle:@"保存文档" forState:UIControlStateNormal];
} else if([sender.titleLabel.text isEqualToString:@"保存文档"]) {
[sender setTitle:@"修改文档" forState:UIControlStateNormal];
self.documentField.placeholder = @"请输入修改的文档内容";
//要保存的文档内容
NSString *dataText = self.documentField.text;
NSData *data = [dataText dataUsingEncoding:NSUTF8StringEncoding];
self.document.data = data;
//保存或创建文档,UIDocumentSaveForOverwriting是覆盖保存文档
[self.document saveToURL:self.document.fileURL
forSaveOperation:UIDocumentSaveForOverwriting
completionHandler:^(BOOL success)
{
NSLog(@"保存成功!");
self.documentShowLable.text = self.documentField.text;
self.documentField.text = @"";
}];
}
}
/* 点击删除文档 */
- (IBAction)removeDocument:(id)sender {
//提示信息
if (self.documentField.text.length <= 0) {
self.documentField.placeholder = @"请输入要删除的文档名";
return;
}
//判断要删除的文档是否存在
NSString *text = self.documentField.text;
NSString *fileName = [NSString stringWithFormat:@"%@.txt",text];
NSArray *fileNames = [self.files allKeys];
if (![fileNames containsObject:fileName]) {
NSLog(@"没有要删除的文档");
return;
}
//创建要删除的文档URL
NSURL *url = [self getUbiquityFileURL:fileName];
NSError *error = nil;
//删除文档文件
[[NSFileManager defaultManager] removeItemAtURL:url error:&error];
if (error) {
NSLog(@"删除文档过程中发生错误,错误信息:%@",error.localizedDescription);
return;
}
//从集合中删除
[self.files removeObjectForKey:fileName];
self.documentField.text = @"";
}
5. 视图控制器初始化和列表显示
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.documentTableView.delegate = self;
self.documentTableView.dataSource = self;
/* 从iCloud上加载所有文档信息 */
[self loadDocuments];
}
#pragma mark - UITableView数据源
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return self.files.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identtityKey = @"myTableViewCellIdentityKey1";
UITableViewCell *cell =
[self.documentTableView dequeueReusableCellWithIdentifier:identtityKey];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:identtityKey];
}
//显示文档名和文档创建日期
NSArray *fileNames = self.files.allKeys;
NSString *fileName = fileNames[indexPath.row];
cell.textLabel.text = fileName;
cell.detailTextLabel.text = [self.files valueForKey:fileName];
return cell;
}
#pragma mark - UITableView代理方法
/* 点击文档列表的其中一个文档调用 */
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.documentTableView cellForRowAtIndexPath:indexPath];
//获取文档URL
NSURL *url = [self getUbiquityFileURL:cell.textLabel.text];
//创建文档操作对象
LTDocument *document = [[LTDocument alloc] initWithFileURL:url];
self.document = document;
//打开文档并读取文档内容
[document openWithCompletionHandler:^(BOOL success) {
if(success){
NSLog(@"读取数据成功.");
NSString *dataText = [[NSString alloc] initWithData:document.data
encoding:NSUTF8StringEncoding];
self.documentShowLable.text = dataText;
}else{
NSLog(@"读取数据失败.");
}
}];
}
@end

iOS学习笔记32-iCloud入门的更多相关文章

  1. iOS学习笔记-地图MapKit入门

    代码地址如下:http://www.demodashi.com/demo/11682.html 这篇文章还是翻译自raywenderlich,用Objective-C改写了代码.没有逐字翻译,如有错漏 ...

  2. iOS学习笔记11-多线程入门

    一.iOS多线程 iOS多线程开发有三种方式: NSThread NSOperation GCD iOS在每个进程启动后都会创建一个主线程,更新UI要在主线程上,所以也称为UI线程,是其他线程的父线程 ...

  3. IOS学习笔记48--一些常见的IOS知识点+面试题

      IOS学习笔记48--一些常见的IOS知识点+面试题   1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...

  4. iOS学习笔记06—Category和Extension

    iOS学习笔记06—Category和Extension 一.概述 类别是一种为现有的类添加新方法的方式. 利用Objective-C的动态运行时分配机制,Category提供了一种比继承(inher ...

  5. iOS学习笔记——AutoLayout的约束

    iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...

  6. IOS学习笔记25—HTTP操作之ASIHTTPRequest

    IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...

  7. IOS学习笔记之关键词@dynamic

    IOS学习笔记之关键词@dynamic @dynamic这个关键词,通常是用不到的. 它与@synthesize的区别在于: 使用@synthesize编译器会确实的产生getter和setter方法 ...

  8. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  9. iOS学习笔记10-UIView动画

    上次学习了iOS学习笔记09-核心动画CoreAnimation,这次继续学习动画,上次使用的CoreAnimation很多人感觉使用起来很繁琐,有没有更加方便的动画效果实现呢?答案是有的,那就是UI ...

  10. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

随机推荐

  1. POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)

    题意: 用一个2*1的骨牌来覆盖一个n*m的矩形,问有多少种方案?(1<=n,m<=11) 思路: 很经典的题目,如果n和m都是奇数,那么答案为0.同uva11270这道题. 只需要m个b ...

  2. 分享一些关于Lucene的心得

    Lucene的概述 Lucene是一个全文搜索框架,而不是应用产品.因此它并不像http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实 ...

  3. springboot 测试

    本次测试使用的是springboot 中的测试 1.(对service 的测试)下面的测试.将会启动容器进行测试 @RunWith(SpringRunner.class) @SpringBootTes ...

  4. 香港城市大学:全球首创3D打印微型机器人技术 有望作治疗癌症用途

    香港城市大学(香港城大)的研究团队开发出了全球首创以磁力控制的3D打印微型机器人,该微型机器人技术能做到在生物体内精准运载细胞到指定的位置.新研发的微型机器人有望应用在治疗癌症的靶向治疗,并为细胞层面 ...

  5. Spring归纳

    Spring总结 bean标签的scope属性 scope="singleton",单例模式,默认值 scope="prototype",多例模式 注解元素 @ ...

  6. docker单主机网络

    当你安装Docker时,它会自动创建三个网络.你可以使用以下docker network ls命令列出这些网络: [root@localhost ~]# docker network ls NETWO ...

  7. Redis五种数据结构解析

    Redis是一个开源的Key-Value存储引擎,它支持string.hash.list.set和sorted set等多种值类型.由于其卓越的性能表现.丰富的数据类型及稳定性,广泛用于各种需要k/v ...

  8. npm上发布包和删除已发布的npm包(https://www.npmjs.com/)

    1.npm上发布自己写的包 2.删除已经发布的包 npm unpublish --force //强制删除,这个是撤销24小时发布的包,有些包发布久了,这个方法不会再管用了. npx force-un ...

  9. linux - 权限解析

    当你在linux下用命令ll 或者ls -la的时候会看到这些字眼,这些字眼表示为不同用户组的权限:r:read就是读权限 --数字4表示w:write就是写权限 --数字2表示 x:excute就是 ...

  10. module.exports exports 和export export default

    首先可以知道的是这是两组不同模块规范. module.exports 是CommonJS模块规范,通过require 导入 a.js: var x = 'hello' module.exports.x ...