iOS学习笔记32-iCloud入门
2018-01-15 13:31
381 查看
一、iCloud云服务
iCloud是苹果提供的云端服务,用户能够将通讯录、备忘录、邮件、照片、音乐、视频等备份到云服务器并在各个苹果设备间直接进行共享而无需关心数据同步问题。甚至即使你的设备丢失后在一台新的设备上也能够通过Apple ID登录同步。苹果已经将云端存储功能开放给开发人员。能够存储两类数据:
key-value data:
分享小量的非关键配置数据到应用的多个实例。使用相似于
NSUserDefault
document:
存储用户文档和应用数据到用户的iCloud账户
进行iCloud开发的准备工作:
在开发人员中心上创建AppleID,启用iCloud服务
生成相应的配置文件(
Provisioning Profile)。这里能够使用通配
Bundle ID
以上2步是针对真机的,调试模拟器能够忽略
打开项目的
Capabilities。找到iCloud服务并开启它
在iCloud服务的
Service中勾选
Key-value storae和
iCloud Documents
你的项目中就会多出一个
entitlements文件
里面的内容是自己主动生成的,就像这种
不管真机还是模拟器,都须要进入手机的设置中登陆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点击,点击改变button */ - (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并指定
searchScopes为
NSMetadataQueryUbiquitousDocumentScope来限制查找iCloud文档数据。
使用
NSMetadataQuery还能够通过谓词限制搜索关键字等信息。并在搜索完毕之后通过通知的形式通知client搜索的情况。
以下是使用演示样例:
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
上面的代码Demo点这里:LearnDemo里面的iCloudDemo
这个代码Demo仅仅有Document的实例代码
假设有什么问题请在下方评论区中提出!
O(∩_∩)O哈。
相关文章推荐
- iOS学习笔记32-iCloud入门
- iOS学习笔记32-iCloud入门
- iOS学习笔记32-iCloud入门
- iOS学习笔记 iCloud入门
- IOS入门学习笔记(普通UI控件--UISwitch、UITextField、UITextView、UISegmentedControl)
- IOS入门学习笔记(普通UI控件--UIButton)
- 《慕客网:IOS-动画入门》学习笔记
- IOS学习笔记32—使用Storyboard实现复杂界面
- IOS学习笔记32—使用Storyboard实现复杂界面
- IOS学习笔记1(入门)——UI继承关系(转)、App生命周期
- 一 :ios学习笔记 OC入门1
- Objective-C学习笔记和IOS入门
- 一 :ios学习笔记 OC入门2 点语法
- IOS学习笔记32—使用Storyboard实现复杂界面
- iOS学习笔记32—本地通知UILocalNotification
- 《慕客网:IOS-动画入门》学习笔记
- IOS学习笔记32—使用Storyboard实现复杂界面
- IOS开发学习笔记(一)——ObjectC语言快速入门
- iOS学习笔记32-iOS 9系统策略更新,使用微信SDK的开发者注意升级
- iOS学习笔记33-UICollectionView入门