2014-10-22 14:37 6137人阅读 评论(6) 收藏 举报

目录(?)[+]

刚开始接触IOS不久,尝试着翻译一些博客,积累技术,与大家共享。

本篇内容讲解的是MagicRecord的使用,是对CoreData的深度封装,原文地址:

http://www.raywenderlich.com/56879/magicalrecord-tutorial-ios 欢迎大家指正,谢谢!

CoreData作为Mac OS 和IOS开发数据持久化和用户数据检索的不可缺少的一部分已经好几年了。为了使API对开发者更容易使用,也为了App的整体化,苹果也在不间断的更新CoreData的API。

也就是说,即使对于一个 精通IOS开发的人CoreData依旧使用起来很困难。即使你会使用CoreData,每天重复性枯燥的使用CoreData也会变得很笨 重,MagicalPanda创建的一个第三方库为这种工作带来了好消息。MagicalRecord 致力于更快捷和容易的使用CoreData。

MagicalRecord 使用方便,特别流行。正如作者所说,MagicalRecord 致力于使CoreData的代码更简洁,更简单的获取数据,并且使用最优化的操作。他是怎么做到的呢?它提供了方便的方法,包含了CoreData使用的 查询更新等的公用模板。它的设计受到了Ruby on Rails'sActiveRecord 持续性系统的影响。

但这些理论已经足够了,请跟着这篇教程来见证MagicalRecord怎样应用。在这篇教程里,你将会创建一个app,该App将记录你所喜爱啤酒的一个踪迹。它将允许你做到以下几个事情:

1.添加你所喜爱的一种啤酒。

2.评价该种啤酒。

3.为该种啤酒添加一个笔记。

4.记录该种啤酒的照片----如果你有太多有意义的记录

入门

要学习本教程,你首先要对 Core Data有基本的理解,只需要了解基础的 Core Data教程,不需要有任何高级的了解。

如果你一点也不了解CoreData,你最好先了解下introductory Core Data tutorial,然后再继续阅读本教程。

首先,请先下载Starter Project,如果已经下载好了,请继续,把工程跑起来,你就可以看到结果。

这是一个带有添加按钮、tableView和搜索栏(下拉table会出现)、可以按照评价或者字母排序的Segment Controller的navigation
controller 。如果你点击了增加按钮,你讲进入并且查看到啤酒的详尽信息,如果你尝试进入其他页面,此信息还未保存。

现在我们看一下代码,在工程的Navigator 里面你将看到:

1.此工程下的所有的ViewController

2.一个ImageSaver 工具类

3.稍后用来初始化数据的图片。

4.一个有一些被UI使用的图片的Images.xcassets库

5.AMRating ---一个用来评价控制的第三方库

6.最后是MagicalRecord

当你看代码的时候,你可能注意到了没有 Core Data模型,在AppDelegate.m里面也不包含任何启动core
data的代码。在启动的时候看不到CoreData对任何工程来说都是最完美的方案,只要记住我们就是在使用CoreData的路上。

使用MagicalRecord开发

         在工程的Navigator栏里面展开MagicalRecord 文件夹,在这个文件夹里面你将会看见Categories
和Core文件夹以及CoreData+MagicalRecord.h文件。展开Categories 文件夹打开 NSManagedObjectModel+MagicalRecord.h.文件你将会发现头文件里面的方法都以 MR_作为前缀。事实上如果你看完了Categories
文件夹里面所有的文件你就会注意到所有的方法都是以MR_作为前缀的。我不知道你为前缀的方式。
     在工程的Navigator栏里面展开Supporting
Files文件夹打开BeerTracker-Prefix.pch文件,该文件是工程的预编译文件,在文件里面增加如下代码:
  1. <span style="font-family:Times New Roman;font-size:14px;">#define MR_SHORTHAND
  2. #import “CoreData+MagicalRecord.h”</span>

这两行代码使得MagicalRecord 在你的工程里面起作用。

1.MR_SHORTHAND 告诉MagicalRecord
你不想在任何的MagicalRecord方法前加MR_前缀。你可以查看MagicalRecord+ShorthandSupport.m文件来查看这句话是怎么起作用的。由于这个已经超出了我们本教程讨论的范围,我们将不在这里讨论它。
2.通过导入CoreData+MagicalRecord.h文件,你可以在你的工程里访问MagicalRecord 的任何一个API,而不用在每一个你需要用到该API的头文件里面导入。
注意:如果你想在你自己的工程里加MagicalRecord ,在GitHub page上有一些小贴士。你也可以按照我在项目里面          加MagicalRecord 的方式来添加。
MagicalRecord 项目。
2.拖拽MagicalRecord 目录到你的XCode工程。
CoreData.framework
包被添加进了你的工程设置里面(Build Phases\Link Binary )
#ifdef
__OBJC__代码的下面添加如下代码:
  1. <span style="font-family:Times New Roman;font-size:14px;">#define MR_SHORTHAND
  2. #import “CoreData+MagicalRecord.h”</span>

为了记录你所喜爱啤酒的踪迹,你将需要一个模型,因为你不能寄希望于自己记住他们,对吧?从Xcode
的菜单栏选中File\New\File…,在列表的左边选中Core
Data 并且从选项里面选中Data Model。


把文件命名为 BeerModel.xcdatamodeld ,放到BeerTracker
文件夹里面。

在工程的导航栏里面选中刚创建的文件 BeerModel.xcdatamodeld来编辑。增加一个名字为Beer的实体(entity ),增加一个类型为String名字为Name的属性。

 
再增加一个名字为BeerDetails的实体,这个实体将记录啤酒的详细信息。例如:用户评价、笔记和在哪里找到图片。用相应的类型给BeerDetails增加下列的属性。

  • Attribute: image Type: String
  • Attribute: note Type: String
  • Attribute: rating Type: Integer
    16


下一步你将创建这两个实体之间的关系(RelationShip),让Beer 实体能够知道那个BeerDetails实例隶属于自己。在BeerDetails实体下面创建一个新的关系(relationship ),命名为“beer”,以Beer为目的(destination) ,通过选择目标“beer”实体,你将建立这两个实体之间的第一部分关系。

通过选择Beer实体来完成建立这个关系。增加一个命名为beerDetails的关系,以BeerDetails为目的(destination)与上面的Beer相对应。现在你的Beer
实体将有一个BeerDetails 实体来对应自己。


下一步是创建类文件来展示实体,这一步你将用到XCode,但是由于Xcode操作的一些怪癖,你需要细心些。

首先在XCode工程的导航栏里面通过选中Core Data模型来编辑它。确保你在ENTITIES 面板里面高亮了Beer实体-------而不是BeerDetails
实体。

下一步是在XCode的菜单栏里面执行Editor\Create
NSManagedObject Subclass… 检查BeerModel,然后选择下一步。然后管理上面的实体,选择Beer和BeerDetail的复选框,如果没有被默认选中,双击确认Beer 是高亮的。点击下一步,并且创建,然后就会生成和上面创建的Beer 和BeerDetails 实体相对应的两个类。留意一下新建的这两个类,你就会发现每个类都有和你刚刚定义的实体属性相对应的属性。

特别留意下,检查下代表两个实体关系的属性,你就会发现Beer类拥有 BeerDetails
*
 类型的一个变量beerDetails ,你还将看到BeerDetails 类有一个NSManagedObject*类型的命名为beer的变量,为什么不是 Beer
*
类型的属性呢?这是因为在Xcode里面“Create
NSManagedObject Subclass”命令的一个限制。这对该工程没有什么影响,因此忽略它吧。

注意:被好奇心折磨着,总是考虑为什么不创建一个Beer
*
CreateNSManagedObjectSubclassCore
Data Model另一个解决方案是让XCode少做一些事,如果你在生成类代码之前已经很明确的在如果你很好奇Xcode怎么从数据模型生成代码,你可以查看Core
Data堆栈了。打开AppDelegate.m文件,在application:didFinishLaunchingWithOptions:方法里面,在return代码前加上下面内容:

  1. // Setup CoreData with MagicalRecord
  2. // Step 1. Setup Core Data Stack with Magical Record
  3. // Step 2. Relax. Why not have a beer? Surely all this talk of beer is making you thirsty…
  4. [MagicalRecord setupCoreDataStackWithStoreNamed:@"BeerModel"];

如果你以前创建过Core Data类型的Xcode工程,你很可能知道在AppDelegate 里面初始化Core
Data需要多少行代码。而使用MagicalRecord你只需要一行代码。

MagicalRecord提供了一些可选的方法来建立你的Core
Data堆栈,可以通过下面的步骤:

1.你的后备存储类型。

2.你是否需要自动迁移。

3.你的Core
Data 模型的名字。

如果你的模型文件和你的工程有一样的基本名称,(比如模型文件的名字是BeerTracker.xcdatamodeld,工程名字是:BeerTracker)

然后你就可以使用MagicalRecord的下列3个方法,setupCoreDataStacksetupCoreDataStackWithInMemoryStore,或者setupAutoMigratingCoreDataStack.

使用名字中有AutoMigrating的方法,你可以改变你的模型,并且可能自动迁移你的存储,MagicalRecord
将帮你操纵这些。通常情况下Core Data则需要你手动添加代码来操作你对模型的一些改变。

调制Beer实体

现在你的Core
Data模型堆栈已经创建起来了,你可以向list里面添加Beer对象了。打开BeerViewController.h文件,在@class
AMRatingControl后面加:

  1. @class Beer;

然后在@interface后面添加一个Beer属性:

  1. @property (nonatomic, strong) Beer *beer;

然后切换到BeerViewController.m,然后在顶部导入 Beer.h 和BeerDetails.h

  1. #import "Beer.h"
  2. #import "BeerDetails.h"

viewDidLoad里面加入以下代码:

  1. - (void)viewDidLoad {
  2. // 1. If there is no beer, create new Beer
  3. if (!self.beer) {
  4. self.beer = [Beer createEntity];
  5. }
  6. // 2. If there are no beer details, create new BeerDetails
  7. if (!self.beer.beerDetails) {
  8. self.beer.beerDetails = [BeerDetails createEntity];
  9. }
  10. // View setup
  11. // 3. Set the title, name, note field and rating of the beer
  12. self.title = self.beer.name ? self.beer.name : @"New Beer";
  13. self.beerNameField.text = self.beer.name;
  14. self.beerNotesView.text = self.beer.beerDetails.note;
  15. self.ratingControl.rating = [self.beer.beerDetails.rating integerValue];
  16. [self.cellOne addSubview:self.ratingControl];
  17. // 4. If there is an image path in the details, show it.
  18. if ([self.beer.beerDetails.image length] > 0) {
  19. // Image setup
  20. NSData *imgData = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:self.beer.beerDetails.image]];
  21. [self setImageForBeer:[UIImage imageWithData:imgData]];
  22. }
  23. }

故障检测:如果你把上面的代码贴到你的工程里面报错了,按快捷键Shift+Command+K
 Clean你的工程。

当BeerViewController 加载时,那是因为你有:

1.或者选择beer或者。。。

2.从MasterViewController 选择添加按钮

当视图加载好后,你将做以下事情:

1.检查beer
实例是否加载好,若没有,这意味你将新建一个Beer

2.如果beer没有任何的BeerDetails,创建一个BeerDetails对象。

3.为了建立视图,抓取beer的名字评价及笔记内容,如果beer没有名字(在Beer的新实例里面,它将给名字为“New
Beer”)

4.如果Beer包含了一个图片路径,将加载该图片到UIImageView里面。
为了编辑和添加新的beers,还有一些事情需要你建立,首先你需要能够编辑和添加名字,像如下方式编辑textFieldDidEndEditing:

  1. - (void)textFieldDidEndEditing:(UITextField *)textField {
  2. if ([textField.text length] > 0) {
  3. self.title = textField.text;
  4. self.beer.name = textField.text;
  5. }
  6. }

现在你将结束添加名字,然后你就可以把beer的名字在文本框内输入为任何内容,只要不空.

为了薄脆笔记内容到 beer的笔记值里面,找到textViewDidEndEditing:方法,向如下编辑

  1. - (void)textViewDidEndEditing:(UITextView *)textView {
  2. [textView resignFirstResponder];
  3. if ([textView.text length] > 0) {
  4. self.beer.beerDetails.note = textView.text;
  5. }
  6. }

下一步确保用户在View Controller里面改变评价,beer的评价会自动更新.在updateRating里面添加:

  1. - (void)updateRating {
  2. self.beer.beerDetails.rating = @(self.ratingControl.rating);
  3. }

当用户在详情页面点击UIImageView,将允许他们添加或者编辑一张图片.一个UIActionSheet 将会展示出来
,它将允许用户下哦那个相机胶卷选择照片,或者拍一张新的照片.如果用户想拍照片,你得确保照片已经保存在磁盘上了.不是吧照片保存在Core Data里面(这将导致性能问题),而是保存在用户的文件目录里面.你只需把图片路径保存在CoreData里面.

通过实现UIImagePickerControllerDelegate 方法,在照片和图库之间管理互动,你需要在UIImagePickerController里面实现BeerViewController 委派,用来在故事板里面操纵视图.找到imagePickerController:didFinishPickingMediaWithinfo,添加如下代码:

  1. - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
  2. // 1. Grab image and save to disk
  3. UIImage *image = info[UIImagePickerControllerOriginalImage];
  4. // 2. Remove old image if present
  5. if (self.beer.beerDetails.image) {
  6. [ImageSaver deleteImageAtPath:self.beer.beerDetails.image];
  7. }
  8. // 3. Save the image
  9. if ([ImageSaver saveImageToDisk:image andToBeer:self.beer]) {
  10. [self setImageForBeer:image];
  11. }
  12. [picker dismissViewControllerAnimated:YES completion:nil];
  13. }

下面讲解下上面的代码:

1.imagePickerController:didFinishPickingMediaWithInfo:间接的传递了用户选择图片的一个参数,,图片是在信息字典里面的,key是UIImagePickerControllerOriginalImage
2.如果Beer图像已经包含了一个图片,程序将把它从硬盘删除.因此你并不会把用户的存储占满.

3.接着新的图片被保存到硬盘,路径被添加到了BeerDetails 的图片属性里面.打开
 ImageSaver 找到saveImageToDisk:andToBeer 看一下
 是什么样子.一旦图片被成功保存,将会在UIImageView里面展现出来

4.选择器消失.

为了使上面的修改器作用,你将修改ImageSaver
,现在你已经创建了Beer 类,你可以取消import行和设置图片路径行的注释.打开ImageSaver.m,修改导入语句如下:

  1. #import "ImageSaver.h"
  2. #import "Beer.h"
  3. #import "BeerDetails.h"

现在你需要取消有if语句这行的注释

  1. if ([imgData writeToFile:jpgPath atomically:YES]) {
  2. beer.beerDetails.image = path;
  3. }

ImageSaver 类已经做好准备来接受图片了.并且保存图片到手机的文件目录里面.保存路径到BeerDetails

从这里开始用户有两个选择,取消或完成,当你创建一个视图,Beer实体就被创建了,然后插入到managedObjectContext里面。取消则会删除Beer
对象。找到cancelAdd,加入如下代码;

  1. - (void)cancelAdd {
  2. [self.beer deleteEntity];
  3. [self.navigationController popViewControllerAnimated:YES];
  4. }

MagicalRecord 提供了一个好的方法来删除实体---从MagicalRecord 里面移出该实体。删除之后用户将返回到beers的主列表。

如果用户选择完成,将保存beer
并返回到主列表。找到addNewBeer,它将简单的pop出view
controller,返回到列表。当视图消失时将调用viewWillDisapper,然后将轮流调用saveContext

saveContext 是空的,因此你需要添加代码来保存新的实体。向saveContext:添加如下代码:

  1. - (void)saveContext {
  2. [[NSManagedObjectContext defaultContext] saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
  3. if (success) {
  4. NSLog(@"You successfully saved your context.");
  5. } else if (error) {
  6. NSLog(@"Error saving context: %@", error.description);
  7. }
  8. }];
  9. }

接下来,还有几行代码要做,在 In AppDelegate.m,
里面用
MagicalRecord建立  Core Data堆栈,这将创建一个app全局可用的默认的managedObjectContext 
对象。当你创建了 Beer 和BeerDetails 实体,他们就被插入到defaultContext 里面了。MagicalRecord 允许你保存任何你可能是使用saveToPersistentStoreWithCompletion:
managedObjectContext 。若保存失败完成的块里面讲给你一个NSError。这里你已经添加了一个简单的if/else块来打印出保存defaultContext时发生的问题。

你想测试一下结果吗?继续运行你的app,选择+按钮,填满内容,选择完成。


这样做之后,在列表的顶部你没有发现新建的Beer,不要急,没问题,你将学会怎样调整问题。你可能发现调试器里面有遗传信息。与你所说的相反,你成功了!

Core Data 堆栈启动期间MagicalRecord 打印出信息,这说明Core
Data 正在启动。然后创建了defaultContext.
对象。这和我们前文提到的你保存beer 对象的是同一个defaultContext.

当你用MagicalRecord选择完成或者保存时,又会出现一系列Log,当你保存时你将看到如下log信息:
1、defaultContext 保存到主线程。
2、任何上下文的父类都将保存,以标志1设计。
3、最后的log显示MagicalRecord 知道两个对象(Beer
和BeerDetail)都将保存,并且被成功保存。
MagicalRecord 为你打印出了很多log,如果你有问题,或者有些事情的表现出乎你的意料,你应该检查日志,来获得有用信息。
注意:
MagicalRecordMagicalRecord.h吧:
  1. #define MR_ENABLE_ACTIVE_RECORD_LOGGING 1
  1. #define MR_ENABLE_ACTIVE_RECORD_LOGGING 0

beers 。打开MasterViewController.m在顶部导入 Beer.h,和 BeerDetails.h

Core Data的Beer,你需要做一些事,viewWillAppear:,里面,在调用 reloadData.之前添加fetch方法。

  1. - (void)viewWillAppear:(BOOL)animated {
  2. [super viewWillAppear:animated];
  3. // Check if the user's sort preference has been saved.
  4. ...
  5. [self fetchAllBeers];
  6. [self.tableView reloadData];
  7. }

当视图第一次加载时,或者从查看或添加beer返回时,将获取和加载所有的beers
到列表中。

找到fetchAllBeers,
加入下列代码:
  1. - (void)fetchAllBeers {
  2. // 1. Get the sort key
  3. NSString *sortKey = [[NSUserDefaults standardUserDefaults] objectForKey:WB_SORT_KEY];
  4. // 2. Determine if it is ascending
  5. BOOL ascending = [sortKey isEqualToString:SORT_KEY_RATING] ? NO : YES;
  6. // 3. Fetch entities with MagicalRecord
  7. self.beers = [[Beer findAllSortedBy:sortKey ascending:ascending] mutableCopy];
  8. }

MasterViewController
允许用户通过评价来排序Beer---从5星到一星,或通过字母排序(A-Z)排序,当App第一次启动时,创建一个NSUserDefault 来通过评价排序,并且作为默认建立起来。在这个方法里面你做如下事情:

1、检索在NSUserDefault 保存的用来排序的key值。
2、如果排序key是”rating“,上升的变量设为否,如果是字幕的变量为是。
3、进行提取
没错这里做的就这莫多。
再来一次,你在使用MagicalRecord 的方法和CoreData交互,findAllSortedBy:ascending 只是用MagicalRecord 执行查找Core
Data 实体中众多方法中的一种,其他的还有(注意:之后你将用到):
  • findAllInContext: –找到上下文提供的所有类型的实体
  • findAll – 找到现在线程上下文对象的所有实体
  • findAllSortedBy:ascending:inContext: –和之前使用的类似但是限制了提供的上下文对象
  • findAllWithPredicate: – 允许你传递谓语动词来搜寻实体。
  • findAllSortedBy:ascending:withPredicate:inContext: –
    允许传递升序标志来排序,允许一个特别的上下文,还允许传递一个谓语动词来过滤结果集

其实还有许多优点,----看一下:NSManagedObject+MagicalFinders.m.

为了在单元里添加beer的名称和评价,找到configureCell:atIndex:,添加下列代码:
  1. - (void)configureCell:(UITableViewCell*)cell atIndex:(NSIndexPath*)indexPath {
  2. // Get current Beer
  3. Beer *beer = self.beers[indexPath.row];
  4. cell.textLabel.text = beer.name;
  5. // Setup AMRatingControl
  6. AMRatingControl *ratingControl;
  7. if (![cell viewWithTag:20]) {
  8. ratingControl = [[AMRatingControl alloc] initWithLocation:CGPointMake(190, 10) emptyImage:[UIImage imageNamed:@"beermug-empty"] solidImage:[UIImage imageNamed:@"beermug-full"] andMaxRating:5];
  9. ratingControl.tag = 20;
  10. ratingControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
  11. ratingControl.userInteractionEnabled = NO;
  12. [cell addSubview:ratingControl];
  13. } else {
  14. ratingControl = (AMRatingControl*)[cell viewWithTag:20];
  15. }
  16. // Put beer rating in cell
  17. ratingControl.rating = [beer.beerDetails.rating integerValue];
  18. }

现在,再找到 prepareForSegue:sender:,
在if语句里检查如果segue标识符是“editBeer,” 添加:

  1. if ([[segue identifier] isEqualToString:@"editBeer"]) {
  2. NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
  3. Beer *beer = self.beers[indexPath.row];
  4. upcoming.beer = beer;
  5. }

这将把Beer对象传递给BeerViewController,
因此就可以展示beer的详细信息,允许编辑等。

继续把你的工程跑起来:
这次你将看到你之前添加的Beer和它的评价,你还可以选择Beer并且编辑信息,当你返回时,列表就更新了。

试着查看某一个Beer,不要编辑信息,返回主列表,看一下log信息你将看到:
-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8b6bfa0) NO CHANGES IN ** DEFAULT ** CONTEXT - NOT SAVING

当你离开详情页,你在viewWillDisappear:. 里面所写的代码将保存默认上下文。然而如果没有变化, MagicalRecord 识别到没有必要执行一个保存操作,因此它跳过了执行。这样做的好处就是,你没有必要考虑你是否应该保存,只需要尝试保存,让 MagicalRecord 给你指出就可以了。

完成触摸
这还有一些你想让app给用户做的事情,比如删除Beer,列出你喜爱啤酒的列表,执行查询。
删除

在 MasterViewController.m,里面找到tableView:commitEditingStyle:forRowAtIndexPath:,
方法添加如下代码:

  1. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
  2. if (editingStyle == UITableViewCellEditingStyleDelete) {
  3. Beer *beerToRemove = self.beers[indexPath.row];
  4. // Remove Image from local documents
  5. if (beerToRemove.beerDetails.image) {
  6. [ImageSaver deleteImageAtPath:beerToRemove.beerDetails.image];
  7. }
  8. // Deleting an Entity with MagicalRecord
  9. [beerToRemove deleteEntity];
  10. [self saveContext];
  11. [self.beers removeObjectAtIndex:indexPath.row];
  12. [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
  13. }
  14. }

记住这里调用了saveContext.方法,你需要添加一些代码来确保删除通过,你已经做过一次了,你能指出怎么做吗?准备。。。开始!

添加如下代码来保存上下文

  1. // Save ManagedObjectContext using MagicalRecord
  2. [[NSManagedObjectContext defaultContext] saveToPersistentStoreAndWait];

严格来说你没必要知道它什么时候结束,你可以使用MagicalRecord
的其他方式来保存managedObjectContext

把App跑起来,删除一个Beer(使用传统的删除cell的方式)如果你重启App,beer就消失了。你做的很对,保存了我们的更改。这意味着你已经正确的使用了 MagicalRecord。拍拍肩膀,放松下。

Demo数据

给用户一些初始化的数据,用户就会很容易明白怎么记录自己喜欢的啤酒,这样会更好。在 AppDelegate.m里面导入 Beer.hBeerDetails.h.
当建立 Core Data堆栈之后加入以下代码:

  1. // Setup App with prefilled Beer items.
  2. if (![[NSUserDefaults standardUserDefaults] objectForKey:@"MR_HasPrefilledBeers"]) {
  3. // Create Blond Ale
  4. Beer *blondAle = [Beer createEntity];
  5. blondAle.name  = @"Blond Ale";
  6. blondAle.beerDetails = [BeerDetails createEntity];
  7. blondAle.beerDetails.rating = @4;
  8. [ImageSaver saveImageToDisk:[UIImage imageNamed:@"blond.jpg"] andToBeer:blondAle];
  9. // Create Wheat Beer
  10. Beer *wheatBeer = [Beer createEntity];
  11. wheatBeer.name  = @"Wheat Beer";
  12. wheatBeer.beerDetails = [BeerDetails createEntity];
  13. wheatBeer.beerDetails.rating = @2;
  14. [ImageSaver saveImageToDisk:[UIImage imageNamed:@"wheat.jpg"] andToBeer:wheatBeer];
  15. // Create Pale Lager
  16. Beer *paleLager = [Beer createEntity];
  17. paleLager.name  = @"Pale Lager";
  18. paleLager.beerDetails = [BeerDetails createEntity];
  19. paleLager.beerDetails.rating = @3;
  20. [ImageSaver saveImageToDisk:[UIImage imageNamed:@"pale.jpg"] andToBeer:paleLager];
  21. // Create Stout
  22. Beer *stout = [Beer createEntity];
  23. stout.name  = @"Stout Lager";
  24. stout.beerDetails = [BeerDetails createEntity];
  25. stout.beerDetails.rating = @5;
  26. [ImageSaver saveImageToDisk:[UIImage imageNamed:@"stout.jpg"] andToBeer:stout];
  27. // Save Managed Object Context
  28. [[NSManagedObjectContext defaultContext] saveToPersistentStoreWithCompletion:nil];
  29. // Set User Default to prevent another preload of data on startup.
  30. [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MR_HasPrefilledBeers"];
  31. [[NSUserDefaults standardUserDefaults] synchronize];
  32. }

在本教程的开始你下载的启动ap,包含了4张灰白色的啤酒照片。在这里你只需要创建4种不同的啤酒,然后保存它们。在NSUserDefaults 里面保存个标志,确保应用里面预先填好数据模型当应用程序第一次启动的时候。

再次运行应用程序,现在你就可以看到所有的新啤酒了。尝试删除一个,然后重新运行Ap,然后删掉的那个就消失了。如果你想再一次看到那几个啤酒,从设备里面删除应用,重新运行应用就可以了。

搜索

现在你已经有超过一种的啤酒,可以测试一下搜索的功能,启动Ap已经包含了一个搜索栏,滑动到列表的头部就可以看到。你所需要做的仅仅是添加搜索啤酒的逻辑。

之前你使用过MagicalRecord 的一个方法来获取所有种类的啤酒。然后她仅仅简单的返回了所有品种的啤酒,现在你需要在所有啤酒里面检索特殊种类的啤酒。

要做到这一点你需要用到谓语动词。之前教程已经讲解了一个使用谓语动词检索的方法。----你能猜出来怎么做吗?逻辑代码在MasterViewController.m 的doSearch 方法里面。

  1. - (void)doSearch {
  2. // 1. Get the text from the search bar.
  3. NSString *searchText = self.searchBar.text;
  4. // 2. Do a fetch on the beers that match Predicate criteria.
  5. // In this case, if the name contains the string
  6. self.beers = [[Beer findAllSortedBy:SORT_KEY_NAME ascending:YES withPredicate:[NSPredicate predicateWithFormat:@"name contains[c] %@", searchText] inContext:[NSManagedObjectContext defaultContext]] mutableCopy];
  7. // 3. Reload the table to show the query results.
  8. [self.tableView reloadData];
  9. }

再次运行Ap将啤酒列表页面向下拽,一直到出现搜索栏。在列表栏里面搜索(列表里有的和没有的),你得到想要的结果了吗?

从这之后干什么

但愿,MagicalRecord 教程能够展示给你使用MagicalRecord
有多么的容易。学会这个样板真的很有用。你在教程里面探索的原理能够帮你开发各种ap,来帮助用户记录他们喜欢的图片,笔记,和评价。多享受啊!
你可以下载完整的代码在这个链接,如果你卡在哪里这将很有帮助。
如果你想进一步开发这个工程,下面是一些想法:
1、在MasterViewController
里面添加“还没创建啤酒”的提示。-----检查并使用MagicalRecord 里面的hasAtLeastOneEntity方法。
2、添加消息提示有多少啤酒匹配搜索条件,使用countOfEntitiesWithPredicate: 方法。
3、完善数据库重置功能-----查看MagicalRecord里面的truncateAll 方法。
4、如果有兴趣打开 MagicalRecordShorthand.h 阅读以下里面的方法是名称----大部分方法的名字都很容易理解,这个头文件应该会给你一些怎么使用MagicalRecord的一些更好的想法。
如果你对本教程有任何问题,或者有任何评论,请加入下面的讨论。
初次翻译,错误之处还请谅解.  完整例子代码见:

http://download.csdn.net/detail/dongtaochen2039/8139455

 

IOS MagicRecord 详解 (转载)的更多相关文章

  1. 【转】IOS AutoLayout详解(三)用代码实现(附Demo下载)

    转载自:blog.csdn.net/hello_hwc IOS SDK详解 前言: 在开发的过程中,有时候创建View没办法通过Storyboard来进行,又需要AutoLayout,这时候用代码创建 ...

  2. IOS SDK详解

    来源:http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html?page=1#42803301 博客专栏>移动开发专栏>I ...

  3. malloc 与 free函数详解<转载>

    malloc和free函数详解   本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...

  4. jQuery的deferred对象详解(转载)

    本文转载自: jQuery的deferred对象详解(转载)

  5. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  6. GridView内容详解(转载)

    GridView内容详解(转载) GridView是ASP.NET界面开发中的一个重要的控件,对GridView使用的熟练程度直接影响软件开发的进度及功能的实现.(车延禄)GridView的主要新特性 ...

  7. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

  8. Linux下的I/O复用与epoll详解(转载)

    Linux下的I/O复用与epoll详解 转载自:https://www.cnblogs.com/lojunren/p/3856290.html  前言 I/O多路复用有很多种实现.在linux上,2 ...

  9. iOS路由详解

    本文如题,路由详解,注定是一篇详细解释iOS路由原理及使用的文章,由于此时正在外地出差,无法详细一一写出,只能不定时的补充. 一.什么是iOS路由 路由一词来源于路由器,可以实现层级之间消息转发的功能 ...

随机推荐

  1. [CodeChef-DGTCNT]Chef and Digits

    题目大意: 若一个十进制数$x$(不含前导零)满足数码$i$恰好出现$t_i$次,则这个数是坏的,否则是好的.求区间$[L,R](1\le L,R\le10^{18})$中有多少好数. 思路: 显然可 ...

  2. 统计正数和负数的个数,然后计算这些数的平均值 Exercise05_01

    import java.util.Scanner; /** * @author 冰樱梦 * * */ public class Exercise05_01{ public static void ma ...

  3. map泛型 map不指定泛型 与 Map<Object,Object>的区别

    map泛型 map不指定泛型 与 Map<Object,Object>的区别 private void viewDetail(){ Map map1 = new HashMap(); Ma ...

  4. u-boot支持LCD显示(基于TQ2440)

    平台简介 Linux版本:Linux-3.14 u-boot版本:u-boot-2015.04 硬件:TQ2440(内存:64MB  NandFlash:256MB) 作者:彭东林 邮箱:pengdo ...

  5. RabbitMq_05_Topics

    Topics (using the .NET client) Prerequisites This tutorial assumes RabbitMQ isinstalled and running ...

  6. 关于ComboGrid取值为非下拉框数据是,隐藏面板数据清空

    $('#areaGuid').combogrid({ panelWidth: 300, idField: 'guid', textField: 'name', mode: 'remote', meth ...

  7. Admin Finder

    #Created for coded32 and his teamopenfire Eliminated Some bugs from my last code shared here as Gues ...

  8. Servlet执行时一般实现哪几个方法?

    public void init(ServletConfig config) public ServletConfig getServletConfig() public String getServ ...

  9. vue - check-versions.js for chalk

    chalk:npm 官网 修改命令输出的文字颜色.粗细等....

  10. vue 预渲染 prerender-spa-plugin

    1.预渲染说明 https://ssr.vuejs.org/zh/#为什么使用服务器端渲染-ssr-? 如果你调研服务器端渲染(SSR)只是用来改善少数营销页面(例如 /, /about, /cont ...