OC开发_Storyboard——Core Data
一 、NSManagedObjectContext
1、我们要想操作Core Data,首先需要一个NSManagedObjectContext
2、那我们如何获得Context呢:创建一个UIManagedDocument
二、UIManagedDocument
1、UIManagedDocument是一系列用于管理存储的机制:
【将Core Data数据库放入某存储空间,相当于是管理core data 数据库的存储,所以我们只需要打开和存储】
2、那我们如何得到UIManagedDocument呢?如何在用户文档中创建一个UIDocument?
//(1文件管理器能够给我们一个用户文件目录的URL
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; //(2然后加上我们想要的文档名
NSString *documentName = @“MyDocument”;
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];
//(3这个URL就是core data数据库存储的地方
UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];
3、但是我们创建的这个文档还并不存在于我们的磁盘中,还需要存储到磁盘
//(1先判断是否已经存在于磁盘
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];!
//(2.1如果已经存在于磁盘,则直接打开
[document openWithCompletionHandler:^(BOOL success) { /* block to execute when open */ }]; !
//(2.2否则还要先存储到磁盘
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating competionHandler:^(BOOL success) { /* block to execute when create is done */ }];
e.g.下面我们看一个综合了上面的具体的例子,如何通过UIManagedDocument得到NSManagedObjectContext:
self.document = [[UIManagedDocument alloc] initWithFileURL:(URL *)url];
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
[document openWithCompletionHandler:^(BOOL success) {
if (success) [self documentIsReady];
if (!success) NSLog(@“couldn’t open document at %@”, url);
}];
} else {
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
if (success) [self documentIsReady];
if (!success) NSLog(@“couldn’t create document at %@”, url);
}];
}
然后我们在 documentIsReady做一些操作从而获得context:
- (void)documentIsReady
{
/*对应的状态有:
UIDocumentStateClosed (还没有打开或者创建)
UIDocumentStateSavingError (completion handler保存没有成功)
UIDocumentStateEditingDisabled (重试)
UIDocumentStateInConflict(例如有其他人在使用更新,有冲突到等)*/ if (self.document.documentState == UIDocumentStateNormal) {
//如果成功的话,我们就获得了我们需要的context了,然后操作core data
NSManagedObjectContext *context = self.document.managedObjectContext;
}
}
4、注意的点
【但要注意的点1:上面UIManagedDocument的打开、关闭或者创建(存储)都是异步执行的】
【需要注意的点2: UIManagedDocument是自动保存的,我们也可以调用上面的自己保存,对应的关闭也是自动关闭的】
【需要注意的点3: UIManagedDocument是多实例的,也就是说可以多控制器同时操作,但对应的同时只有一个可写】
5、广播站:
比如我们在一个文档中修改了数据CoreData,但是同时 另一个并没有能马上看到,这是因为它们所用的Context不同,要想能看到需要使用NSNotiFication广播站
三、NSNotiFication广播站
1、如何注册一个广播
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[center addObserver:self
selector:@selector(contextChanged:)
name:NSManagedObjectContextDidSaveNotification
object:document.managedObjectContext]; // don’t pass nil here!
}
- (void)viewWillDisappear:(BOOL)animated
{
[center removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:document.managedObjectContext];
[super viewWillDisappear:animated];
}
2、广播得到消息之后能做什么?如何在contextChanged里操作?
(1 可以取回我的所有对象
- (void)contextChanged:(NSNotification *)notification
{
// notification.userInfo 返回给我们的是一个字典包含以下的key
NSInsertedObjectsKey //插入的对象数组
NSUpdatedObjectsKey // 有属性更改的对象数组
NSDeletedObjectsKey // 有删除的对象数组
}
(2 Merging changes:只要把notification传给它,它会自动帮我们把所有的变化合并到我们的context中
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification;
四、Core Data
上面的操作都完备,我们就可以对我们的数据库进行增删改的操作了
【这些操作是在内存中,不是在磁盘,但是别忘记了Document是自动保存的,所以最终还是会保存到磁盘的,只要文档保存了,Context就保存了】
1、插入
NSManagedObjectContext *context = aDocument.managedObjectContext;
//实体的名称:@“EntityBook”,返回NSManagedObject对象【数据库所有对象都是它或者它的子类】
NSManagedObject *book = [NSEntityDescription insertNewObjectForEntityForName:@“EntityBook” inManagedObjectContext:context];
//设置属性
- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;
或者也可以用:valueForKeyPath:/setValue:forKeyPath
设置属性例如:
NSString *myThumbnail = book.thumbnailURL;
book.lastViewedDate = [NSDate date];
book.whoTook = ...; //这里的whoTook指的是另一张表的关联关系
book.whoTook.name = @“CS193p Instructor”;
2、删除
//(1要注意的是这也不是马上删除,而是需要在自动保存之后才会删除,但是引用到book的地方需要在这个操作之后设置为nil
[aDocument.managedObjectContext deleteObject:book];
//(2 这个方法通常放在类别中,用于删除操作之后的某些更新
- (void)prepareForDeletion{}
3、查询
(1 NSFetchRequest 提出请求从数据库请求对象
指定要取回的实体、指定取回的对象大小数量、NSSortDescriptors排序、NSPredicate谓词哪一些数据
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“EntityBook”];
request.fetchBatchSize = 20;
request.fetchLimit = 100;
request.sortDescriptors = @[sortDescriptor];
request.predicate = ...;
(2 NSSortDescriptor 排序
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@“title” //排序的键
ascending:YES //YES是按字母排序,NO是反字母排序
selector:@selector(localizedStandardCompare:)]; //在排序中的对比,这里的localizedStandardCompare 指代像Mac finder中的排序方式一般
(3 NSPredicate谓词
NSString *serverName = @“IOS-”;
NSPredicate *predicate =
[NSPredicate predicateWithFormat:@“bookName contains %@”, serverName]; @“uniqueId = %@”, [flickrInfo objectForKey:@“id”]
@“name contains[c] %@”, (NSString *)
@“viewed > %@”, (NSDate *)
@“whoTook.name = %@”, (NSString *)
@“any photos.title contains %@”, (NSString *)
@“(name = %@) OR (title = %@)”
@“photos.@count > ”
@“photos.photo.title.length"
[propertyListResults valueForKeyPath:@“photos.photo.@avg.latitude”] // 复合谓词
NSArray *array = @[predicate1, predicate2];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:array];
更多的使用可以查询:
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html.
demo请求的例子:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photographer”];
NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow:-**];
request.predicate = [NSPredicate predicateWithFormat:@“any photos.uploadDate > %@”, yesterday];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@“name” ascending:YES]]; NSManagedObjectContext *context = aDocument.managedObjectContext;
NSError *error;
NSArray *photographers = [context executeFetchRequest:request error:&error];
五. 生成实体的类
1、方法
Editor->Create NSManagedObject Subclass => 选择Model => 选择要生成的数据表EntityBook
2、可以修改这些系统生成的类?=> 最好不要,我们可以采用类别的方法,也就是Categories
【Categories类别可以添加方法到一个类,而不用创建它额的子类,你甚至不需要有该类的源代码】
六、Categories类别
【不能使用实例变量或者任何存储数据】
1、声明
@interface EntityBook (AddOn)
- (NSString *)note;
@property (readonly) BOOL isOld;
@end
2、实现
@implementation EntityBook (AddOn)
- (NSString *)note //要注意:note不是数据库表的属性,但是这里的bookName uploadDate是属性
{
NSString *bookNote = [NSString stringWithFormat:@"%@:lalalallal", self.bookName];
return bookNote;
}
- (BOOL)isOld //
{
return [self.uploadDate timeIntervalSinceNow] > -**;
}
@end
3、大多数情况下的实现
@implementation EntityBook (Create) + (EntityBook *)bookWithData:(NSDictionary *)Data inManagedObjectContext:(NSManagedObjectContext *)context
{
EntityBook *book = ...; // 查看具体某一本书是否存在
if (!book)
{
book = [NSEntityDescription insertNewObjectForEntityForName:@“EntityBook” inManagedObjectContext:context];
}
return book;
}
@end
七、线程安全
1、NSManagedObjectContext并不线程安全,任何使用在下面的BLock里面去执行 它会对Context在安全队列中执行
[context performBlock:^{ or performBlockAndWait:
//使用对Context做的事情,例如插入对象、查询等等
}];
八、NSFetchedResultsController
[使得Core Data和UITableViewController能够相辅相成。]
1、例如:
- (NSUInteger)numberOfSectionsInTableView:(UITableView *)sender
{
return [[self.fetchedResultsController sections] count];
}
- (NSUInteger)tableView:(UITableView *)sender numberOfRowsInSection:(NSUInteger)section
{
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)sender cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...;
// 或者 Book *book = (Book *) ...
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
return cell;
}
2、那么如何构建一个NSFetchedResultsController呢?
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“EntityBook”];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@“title” ...]];
//关联另一张表的查询,比如说作者表中的作者名称,作为我们book表的WhoTook
request.predicate = [NSPredicate predicateWithFormat:@“whoTook.name = %@”, authorName];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc]
initWithFetchRequest:(NSFetchRequest *)request
managedObjectContext:(NSManagedObjectContext *)context
sectionNameKeyPath:(NSString *)keyThatSaysWhichSectionEachManagedObjectIsIn
cacheName:@“MyPhotoCache”// 指定为nil的话,就不会执行缓存处理[永久性在磁盘中]:所以只针对总有相同FetChRequest的TableView
];
3、让NSFetchwsResultController和TableView关联起来有两种方式,一种是利用它实现所有UITableViewDataSource的东西
第二种就是设置委托:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
// 更新TableView[可以利用CoreDataTableViewController]
}
4、CoreDataTableViewController
OC开发_Storyboard——Core Data的更多相关文章
- ios开发:Core Data概述
Core Data 概述 2005年的四月份,Apple 发布了 OS X 10.4,在这个版本中 Core Data 框架发布了.Core Data本身既不是数据库也不是数据库访问框架.相反,Cor ...
- OC开发_Storyboard——MapKit
一.Core Location 1.基本对象 @propertys: coordinate, altitude, horizontal/verticalAccuracy, timestamp, sp ...
- OC开发_Storyboard——iPad开发
iPad开发(Universal Applications) 一.iPad 1.判断是否在iPad上 BOOL iPad = ([[UIDevice currentDevice] userInterf ...
- OC开发_Storyboard——AutoLayout
一.autolayout 自动布局: 1. 设置所有视图框架的三种方法,可以通过代码创建也可以storyboard设置 = 规则 (1 蓝线+约束:(位置) 使用蓝线,根据蓝线拖动控件,只是告诉Xco ...
- OC开发_Storyboard——多线程、UIScrollView
一.多线程 1.主队列:处理多点触控和所有UI操作(不能阻塞.主要同步更新UI) dispatch_queue_t mainQueue = dispatchg_get_main_queue(); // ...
- OC开发_Storyboard——UITableView
一.tableView 1.datasource数据源 (1 构造每一个tableVIewCell的方法:cellForRowAtIndexPath,这里的 dequeueReusableCellWi ...
- OC开发_Storyboard——UIApplication和网络活动指示器
一.UIApplication 只有一个实例: UIApplication *myApplication = [UIApplication sharedApplication]; 属性如果设置为YES ...
- OC开发_Storyboard——绘制和视图
1.绘制 不要调用drawRect.调用setNeedsDisplay相当于告知系统视图需要重绘, 它会去调用drawRect,更新屏外缓冲器 2.UIBezierPath绘制图形, 设置图像op ...
- OC开发_Storyboard——block和动画
一.协议 @optional :可选的 @requied :必须实现的 二.block 代码块 1. 以一个^开头,然后是参数,然后是一个大括号,包含我们的代码块 [aDictionary enu ...
随机推荐
- CI循环数组问题
当我们在Controll中把数据传递到view中如: $data['cates_data']=$this->Category_Model->byid_data($id); #调用模型层查询 ...
- thinkphp 查询指定分类下的文章
$list = $Dao->query("SELECT xp_wztj.bt,xp_wztj.time,xp_wztj.gjz,xp_wztj.wz,xp_wzfl.name FROM ...
- 关于Cocos2d-x中坐标系的种类和转换
注意: 当一个节点有一个子节点的时候,如果移动父节点,子节点也会跟着做相应的移动变化,只要被添加到父节点中,子节点就被绑定了,所以子节点的位置,坐标就会被动地变化. 当一个节点有一个子节点的时候,如果 ...
- Read from socket failed: Connection reset by peer 问题
[FAILED] 解决方法:#chmod 600 sshd_config ssh_host_dsa_key ssh_host_key ssh_host_rsa_key#chmod 620 moduli ...
- mpeg压缩输入格式---打包模式和平面模式
版本 v1.0,存在内存问题在 void v4l2_process_image(struct buffer buf)中对 v4l2 采集来的一帧进行处理,存在 struct buffer buf 中b ...
- QLayout布局时自动占满全部的空间。
QLayout子类布局时会自动占满全部的空间,和一般需要多大空间占多大空间的要求不符合,很烦人. 案例: 本来一个容器简单的放几个组件会剩余很大的空间,就那么剩余就好.
- CentOS tree命令详解
inux下tree命令详解---linux以树状图逐级列出目录的内容命令 ############################################################### ...
- window用Xmanager4.0的Xstart连接linux远程桌面
安装包: xorg-x11-xauth xterm.x86_64 0:253-1.el6 Execute command path:/usr/bin/xterm Xstart连接Linux远程桌面有一 ...
- [kfaka] Apache Kafka:下一代分布式消息系统
简介 Apache Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,之后成为Apache项目的一部分.Kafka是一种快速.可扩展的.设计内在就是分布式的,分区的和可复制的提交 ...
- opencv-从图像旋转学习Mat数据訪问
先看一个简单的样例 代码: // ConsoleApplication3_6_23.cpp : Defines the entry point for the console application. ...