OC开发_Storyboard——Core Data

一 、NSManagedObjectContext

1、我们要想操作Core Data,首先需要一个NSManagedObjectContext
2、那我们如何获得Context呢:创建一个UIManagedDocument

二、UIManagedDocument

1、UIManagedDocument是一系列用于管理存储的机制:
  【将Core Data数据库放入某存储空间,相当于是管理core data 数据库的存储,所以我们只需要打开和存储】
2、那我们如何得到UIManagedDocument呢?如何在用户文档中创建一个UIDocument?

1 //(1文件管理器能够给我们一个用户文件目录的URL
2 NSFileManager *fileManager = [NSFileManager defaultManager];
3 NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
4
5 //(2然后加上我们想要的文档名
6 NSString *documentName = @“MyDocument”;
7 NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];
8 //(3这个URL就是core data数据库存储的地方
9 UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];

3、但是我们创建的这个文档还并不存在于我们的磁盘中,还需要存储到磁盘

1 //(1先判断是否已经存在于磁盘
2 BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];!
3 //(2.1如果已经存在于磁盘,则直接打开
4 [document openWithCompletionHandler:^(BOOL success) { /* block to execute when open */ }]; !
5 //(2.2否则还要先存储到磁盘
6 [document saveToURL:url forSaveOperation:UIDocumentSaveForCreating competionHandler:^(BOOL success) { /* block to execute when create is done */ }];

e.g.下面我们看一个综合了上面的具体的例子,如何通过UIManagedDocument得到NSManagedObjectContext:

 1 self.document = [[UIManagedDocument alloc] initWithFileURL:(URL *)url];
 2 if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
 3     [document openWithCompletionHandler:^(BOOL success) {
 4         if (success) [self documentIsReady];
 5         if (!success) NSLog(@“couldn’t open document at %@”, url);
 6     }];
 7 } else {
 8     [document saveToURL:url forSaveOperation:UIDocumentSaveForCreating
 9       completionHandler:^(BOOL success) {
10           if (success) [self documentIsReady];
11           if (!success) NSLog(@“couldn’t create document at %@”, url);
12       }];
13 }

然后我们在 documentIsReady做一些操作从而获得context:

 1 - (void)documentIsReady
 2 {
 3     /*对应的状态有:
 4    UIDocumentStateClosed (还没有打开或者创建)
 5    UIDocumentStateSavingError (completion handler保存没有成功)
 6    UIDocumentStateEditingDisabled (重试)
 7    UIDocumentStateInConflict(例如有其他人在使用更新,有冲突到等)*/
 8
 9    if (self.document.documentState == UIDocumentStateNormal) {
10        //如果成功的话,我们就获得了我们需要的context了,然后操作core data
11        NSManagedObjectContext *context = self.document.managedObjectContext;
12    }
13 }

4、注意的点
【但要注意的点1:上面UIManagedDocument的打开、关闭或者创建(存储)都是异步执行的】
【需要注意的点2: UIManagedDocument是自动保存的,我们也可以调用上面的自己保存,对应的关闭也是自动关闭的】
【需要注意的点3: UIManagedDocument是多实例的,也就是说可以多控制器同时操作,但对应的同时只有一个可写】

5、广播站:
比如我们在一个文档中修改了数据CoreData,但是同时 另一个并没有能马上看到,这是因为它们所用的Context不同,要想能看到需要使用NSNotiFication广播站

三、NSNotiFication广播站

1、如何注册一个广播

 1 - (void)viewDidAppear:(BOOL)animated
 2 {
 3    [super viewDidAppear:animated];
 4    [center addObserver:self
 5               selector:@selector(contextChanged:)
 6                   name:NSManagedObjectContextDidSaveNotification
 7                 object:document.managedObjectContext]; // don’t pass nil here!
 8 }
 9 - (void)viewWillDisappear:(BOOL)animated
10 {
11     [center removeObserver:self
12                       name:NSManagedObjectContextDidSaveNotification
13                     object:document.managedObjectContext];
14     [super viewWillDisappear:animated];
15 }

2、广播得到消息之后能做什么?如何在contextChanged里操作?

(1 可以取回我的所有对象

1 - (void)contextChanged:(NSNotification *)notification
2 {
3     //  notification.userInfo 返回给我们的是一个字典包含以下的key
4     NSInsertedObjectsKey //插入的对象数组
5     NSUpdatedObjectsKey // 有属性更改的对象数组
6     NSDeletedObjectsKey // 有删除的对象数组
7 }

(2 Merging changes:只要把notification传给它,它会自动帮我们把所有的变化合并到我们的context中
   - (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification;

四、Core Data

上面的操作都完备,我们就可以对我们的数据库进行增删改的操作了
【这些操作是在内存中,不是在磁盘,但是别忘记了Document是自动保存的,所以最终还是会保存到磁盘的,只要文档保存了,Context就保存了】

1、插入

1    NSManagedObjectContext *context = aDocument.managedObjectContext;
2    //实体的名称:@“EntityBook”,返回NSManagedObject对象【数据库所有对象都是它或者它的子类】
3    NSManagedObject *book = [NSEntityDescription insertNewObjectForEntityForName:@“EntityBook” inManagedObjectContext:context];
4    //设置属性
5    - (id)valueForKey:(NSString *)key;
6    - (void)setValue:(id)value forKey:(NSString *)key;
7    或者也可以用: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 排序

1 NSSortDescriptor *sortDescriptor =
2         [NSSortDescriptor sortDescriptorWithKey:@“title”  //排序的键
3                                       ascending:YES       //YES是按字母排序,NO是反字母排序
4                                        selector:@selector(localizedStandardCompare:)]; //在排序中的对比,这里的localizedStandardCompare 指代像Mac finder中的排序方式一般
5    

(3 NSPredicate谓词

 1     NSString *serverName = @“IOS-7”;
 2     NSPredicate *predicate =
 3     [NSPredicate predicateWithFormat:@“bookName contains %@”, serverName];
 4
 5     @“uniqueId = %@”, [flickrInfo objectForKey:@“id”]
 6     @“name contains[c] %@”, (NSString *)
 7     @“viewed > %@”, (NSDate *)
 8     @“whoTook.name = %@”, (NSString *)
 9     @“any photos.title contains %@”, (NSString *)
10     @“(name = %@) OR (title = %@)”
11     @“photos.@count > 5”
12     @“photos.photo.title.length"
13     [propertyListResults valueForKeyPath:@“photos.photo.@avg.latitude”]
14
15        // 复合谓词
16     NSArray *array = @[predicate1, predicate2];
17     NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:array];

更多的使用可以查询:
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html.

demo请求的例子:

1     NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photographer”];
2     NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow:-24*60*60];
3     request.predicate = [NSPredicate predicateWithFormat:@“any photos.uploadDate > %@”, yesterday];
4     request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@“name” ascending:YES]];
5
6     NSManagedObjectContext *context = aDocument.managedObjectContext;
7     NSError *error;
8     NSArray *photographers = [context executeFetchRequest:request error:&error]; 

五. 生成实体的类

1、方法
Editor->Create NSManagedObject Subclass => 选择Model => 选择要生成的数据表EntityBook

2、可以修改这些系统生成的类?=> 最好不要,我们可以采用类别的方法,也就是Categories
【Categories类别可以添加方法到一个类,而不用创建它额的子类,你甚至不需要有该类的源代码】

六、Categories类别

【不能使用实例变量或者任何存储数据】
1、声明

1 @interface EntityBook (AddOn)
2 - (NSString *)note;
3 @property (readonly) BOOL isOld;
4 @end

2、实现

 1 @implementation EntityBook (AddOn)
 2 - (NSString *)note //要注意:note不是数据库表的属性,但是这里的bookName uploadDate是属性
 3 {
 4    NSString *bookNote = [NSString stringWithFormat:@"%@:lalalallal", self.bookName];
 5    return bookNote;
 6 }
 7 - (BOOL)isOld //
 8 {
 9    return [self.uploadDate timeIntervalSinceNow] > -24*60*60;
10 }
11 @end

3、大多数情况下的实现

 1 @implementation EntityBook (Create)
 2
 3 + (EntityBook *)bookWithData:(NSDictionary *)Data inManagedObjectContext:(NSManagedObjectContext *)context
 4 {
 5    EntityBook *book = ...; // 查看具体某一本书是否存在
 6    if (!book)
 7    {
 8       book = [NSEntityDescription insertNewObjectForEntityForName:@“EntityBook” inManagedObjectContext:context];
 9    }
10    return book;
11 }
12 @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

时间: 2024-12-24 14:47:26

OC开发_Storyboard——Core Data的相关文章

ios开发:Core Data概述

Core Data 概述 2005年的四月份,Apple 发布了 OS X 10.4,在这个版本中 Core Data 框架发布了.Core Data本身既不是数据库也不是数据库访问框架.相反,Core Data是一个完整的数据模型解决方案.可以简单理解为对持久层的封装,使得我们可以通过可视化建立数据模型,简化数据存取.即使不懂SQL语句,也依然可以使用Core Data.因为Core Data将底层的数据库SQL语句封装成了一套API,并可通过可视化操作来建立数据库的模型和表之间的关系,它甚至

IOS开发之--Core Data的使用(进阶)

CoreData的使用(进阶) 本次目标是创建一个应用程序,可以记录每次你保存的经纬度坐标,并且可以对这些坐标(我们保存为一个Event实体)进行编辑. 建立工程 步骤 创建一个Empty Application,起名叫Locations,选择Devices为iPhone,并且使用ARC: 添加CoreLocation.framework: 添加一个Storyboard文件,并在工程属性中选择Main Storyboard为这个文件: 至此,操作步骤完成. 对工程的理解 以上步骤完成后,我们的工

IOS开发之--Core Data的使用

Core Data基础知识 官方的说法是:Core Data is a schema-driven object graph management and persistence framework. 翻译过来的意思大概是:Core Data是一个模式驱动的对象图管理和持久化框架. 好吧,上面的字面意思不是很容易理解,那么我们从以下几个方面来帮助那些有其余开发经验的程序员树立一些观念: Core Data不是一个数据库,但是他可能使用一个数据库.默认情况下,Core Data将使用SQLite,

OC开发_Storyboard——iPad开发

iPad开发(Universal Applications) 一.iPad 1.判断是否在iPad上 BOOL iPad = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad); 二.UISplitViewController 分割视图控制器 1.UISplitViewController 分割视图控制器(顶级视图,不能放在Nav或者其他视图中) (1  可以通过 if (self.splitVie

OC开发_Storyboard——MapKit

一.Core  Location 1.基本对象 @propertys: coordinate, altitude, horizontal/verticalAccuracy, timestamp, speed, course @property (readonly) CLLocationCoordinate2D coordinate; typedef { CLLocationDegrees latitude; //   double型 纬度 CLLocationDegrees longitude;

OC开发_Storyboard——AutoLayout

一.autolayout 自动布局: 1. 设置所有视图框架的三种方法,可以通过代码创建也可以storyboard设置 = 规则 (1 蓝线+约束:(位置) 使用蓝线,根据蓝线拖动控件,只是告诉Xcode我要这样设置,但是还需要Xcode为我们执行相应的规则和约束 Reset to Sugested Constrains in VIew Controller(前提是使用了蓝线) (2 点击底部菜单按钮:Add New Alignments Constraints 具体设置(需要 update f

OC开发_Storyboard——block和动画

 一.协议 @optional :可选的 @requied :必须实现的  二.block 代码块 1. 以一个^开头,然后是参数,然后是一个大括号,包含我们的代码块 1 [aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { 2 NSLog(@“value for key %@ is %@”, key, value); 3 if ([@“ENOUGH” isEqualToString:ke

OC开发_Storyboard——绘制和视图

1.绘制 不要调用drawRect.调用setNeedsDisplay相当于告知系统视图需要重绘, 它会去调用drawRect,更新屏外缓冲器 2.UIBezierPath绘制图形,   设置图像opaque属性=no,根据透明度一层层合成视图,比直接修改比特值的开销会大很大多,消耗性能   如果只是显示的问题可以通过设置hidden 3.UIGestureRecognizer setNeedDisplay是为了让有人修改时重绘 ,据目标大小,选择合适尺寸 现在利用绘制做一个小demo,效果如下

OC开发_Storyboard——UITableView

一.tableView 1.datasource数据源 (1 构造每一个tableVIewCell的方法:cellForRowAtIndexPath,这里的 dequeueReusableCellWithIdentifier会根据识别ID去取storyBoard中的cell,同时这也是利用取缓存中的cell复用 (2 还包含了另外两个方法,numberOfSectionsInTableView 默认是返回1如果不重写它的话:numberOfRowsInSection是没有默认值的,所以实现数据源