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 ...
随机推荐
- Translating between qplot and base graphics
Translating between qplot and base graphics Description There are two types of graphics functions in ...
- 让IE6支持min-height,max-height等的方法
1.IE6支持max-height解决方法 IE6支持最大高度解决CSS代码:.yangshi{max-height:1000px;_height:expression((document.do ...
- Java String 学习
String, 首先,String有字面值常量的概念,这个字面值常量是在编译期确定下来的,类加载时直接存入常量池(注意,常量池是类的常量池,类与类之间隔离). 而运行时生成的字符串,是不在常量池中的. ...
- e578. Setting the Clipping Area with a Shape
This example demonstrates how to set a clipping area using a shape. The example sets an oval for the ...
- e556. 在程序中播放音频
try { URL url = new URL("http://hostname/audio.au"); AudioClip ac = Applet.newAudioClip(ur ...
- RequireJS使用小结1——for Effective JavaScript Module Loading
1. require和define的区别 The require() function is used to run immediate functionalities, while define() ...
- linux -- Ubuntu下安装和配置Apache2
在Ubuntu中安装apache 安装指令:sudo apt-get install apache2 启动和停止apache的文件是:/etc/init.d/apache2 启动命令:sudo apa ...
- SharePoint 2010用“localhost”方式访问网站,File not found问题处理方式
场景:本地服务器上,用“localhost”方式访问网站:在某网站集(Site Collection)下的子网站(Sub Site)中,点击网站权限菜单(Site permissions)等关于调用L ...
- Ubuntu 安装 Kubernetes
Kubernetes是Google开源的容器集群管理系统.它构建于docker技术之上,为容器化的应用提供资源调度.部署运行.服务发现.扩容缩容等整一套功能,本质上可看作是基于容器技术的mini-Pa ...
- 为什么MathType窗口变灰色
mathtype是一个功能强大的数学公式编辑器,可以轻松输入各种复杂的公式和符号,与Office文档完美结合,显示效果超好,比Office自带的公式编辑器要强大很多.但我们在使用MathType编辑公 ...