MagicRecord

刚开始接触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.此工程下的所有的ViewController2.一个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文件,该文件是工程的预编译文件,在文件里面增加如下代码:[html] view plain copy#define MR_SHORTHAND

#import “CoreData+MagicalRecord.h”这两行代码使得MagicalRecord 在你的工程里面起作用。1.MR_SHORTHAND 告诉MagicalRecord 你不想在任何的MagicalRecord方法前加MR_前缀。你可以查看MagicalRecord+ShorthandSupport.m文件来查看这句话是怎么起作用的。由于这个已经超出了我们本教程讨论的范围,我们将不在这里讨论它。2.通过导入CoreData+MagicalRecord.h文件,你可以在你的工程里访问MagicalRecord 的任何一个API,而不用在每一个你需要用到该API的头文件里面导入。注意:如果你想在你自己的工程里加MagicalRecord ,在 GitHub page上有一些小贴士。你也可以按照我在项目里面          加MagicalRecord 的方式来添加。1.从GitHub上面下载MagicalRecord 项目。2.拖拽MagicalRecord 目录到你的XCode工程。3.确保CoreData.framework 包被添加进了你的工程设置里面(Build Phases\Link Binary )4.在你工程预编译头文件#ifdef __OBJC__代码的下面添加如下代码:[html] view plain copy#define MR_SHORTHAND

#import “CoreData+MagicalRecord.h”啤酒模型为了记录你所喜爱啤酒的踪迹,你将需要一个模型,因为你不能寄希望于自己记住他们,对吧?从Xcode 的菜单栏选中File\New\File…,在列表的左边选中Core Data 并且从选项里面选中Data Model。把文件命名为 BeerModel.xcdatamodeld ,放到BeerTracker 文件夹里面。在工程的导航栏里面选中刚创建的文件 BeerModel.xcdatamodeld来编辑。增加一个名字为Beer的实体(entity ),增加一个类型为String名字为Name的属性。 再增加一个名字为BeerDetails的实体,这个实体将记录啤酒的详细信息。例如:用户评价、笔记和在哪里找到图片。用相应的类型给BeerDetails增加下列的属性。Attribute: image Type: StringAttribute: note Type: StringAttribute: 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 * 类型的变量,看起来,这貌似是Xcode里面CreateNSManagedObjectSubclass命令的限制。自从Xcode有了Core Data Model,这个命令就应该合乎情理的推断出在彼此的关系里,每一个类的属性都应该包含其他类的类型。然而这个命令不止用来生成类的属性,也被用来生成用来定义这些类型的类的名称,而这个命令并没有智能到来吧两件事情都处理好。一个解决方案是简单的调整一下生成代码,给确定的类设置属性。另一个解决方案是让XCode少做一些事,如果你在生成类代码之前已经很明确的在Data Model Inspector里面定义了类名,XCode将生成正确的类属性。如果你很好奇Xcode怎么从数据模型生成代码,你可以查看mogenerator现在你已经创建了Object数据类。是时候初始化 Core Data堆栈了。打开AppDelegate.m文件,在application:didFinishLaunchingWithOptions:方法里面,在return代码前加上下面内容:[objc] view plain copy// Setup CoreData with MagicalRecord  // Step 1. Setup Core Data Stack with Magical Record  // Step 2. Relax. Why not have a beer? Surely all this talk of beer is making you thirsty…  [MagicalRecord setupCoreDataStackWithStoreNamed:@"BeerModel"];  如果你以前创建过Core Data类型的Xcode工程,你很可能知道在AppDelegate 里面初始化Core Data需要多少行代码。而使用MagicalRecord你只需要一行代码。MagicalRecord提供了一些可选的方法来建立你的Core Data堆栈,可以通过下面的步骤:1.你的后备存储类型。2.你是否需要自动迁移。3.你的Core Data 模型的名字。如果你的模型文件和你的工程有一样的基本名称,(比如模型文件的名字是BeerTracker.xcdatamodeld,工程名字是:BeerTracker)然后你就可以使用MagicalRecord的下列3个方法,setupCoreDataStack, setupCoreDataStackWithInMemoryStore,或者setupAutoMigratingCoreDataStack.使用名字中有AutoMigrating的方法,你可以改变你的模型,并且可能自动迁移你的存储,MagicalRecord 将帮你操纵这些。通常情况下Core Data则需要你手动添加代码来操作你对模型的一些改变。调制Beer实体现在你的Core Data模型堆栈已经创建起来了,你可以向list里面添加Beer对象了。打开BeerViewController.h文件,在@class AMRatingControl后面加:[objc] view plain copy@class Beer;  然后在@interface后面添加一个Beer属性:[objc] view plain copy@property (nonatomic, strong) Beer *beer;  然后切换到BeerViewController.m,然后在顶部导入 Beer.h 和BeerDetails.h[objc] view plain copy#import "Beer.h"  #import "BeerDetails.h"  在viewDidLoad里面加入以下代码:[objc] view plain copy- (void)viewDidLoad {      // 1. If there is no beer, create new Beer      if (!self.beer) {          self.beer = [Beer createEntity];      }      // 2. If there are no beer details, create new BeerDetails      if (!self.beer.beerDetails) {          self.beer.beerDetails = [BeerDetails createEntity];      }      // View setup      // 3. Set the title, name, note field and rating of the beer      self.title = self.beer.name ? self.beer.name : @"New Beer";      self.beerNameField.text = self.beer.name;      self.beerNotesView.text = self.beer.beerDetails.note;      self.ratingControl.rating = [self.beer.beerDetails.rating integerValue];      [self.cellOne addSubview:self.ratingControl];        // 4. If there is an image path in the details, show it.      if ([self.beer.beerDetails.image length] > 0) {          // Image setup          NSData *imgData = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:self.beer.beerDetails.image]];          [self setImageForBeer:[UIImage imageWithData:imgData]];      }  }  故障检测:如果你把上面的代码贴到你的工程里面报错了,按快捷键Shift+Command+K  Clean你的工程。当BeerViewController 加载时,那是因为你有:1.或者选择beer或者。。。2.从MasterViewController 选择添加按钮当视图加载好后,你将做以下事情:1.检查beer 实例是否加载好,若没有,这意味你将新建一个Beer2.如果beer没有任何的BeerDetails,创建一个BeerDetails对象。3.为了建立视图,抓取beer的名字评价及笔记内容,如果beer没有名字(在Beer的新实例里面,它将给名字为“New Beer”)4.如果Beer包含了一个图片路径,将加载该图片到UIImageView里面。为了编辑和添加新的beers,还有一些事情需要你建立,首先你需要能够编辑和添加名字,像如下方式编辑textFieldDidEndEditing:[objc] view plain copy- (void)textFieldDidEndEditing:(UITextField *)textField {      if ([textField.text length] > 0) {          self.title = textField.text;          self.beer.name = textField.text;      }  }  现在你将结束添加名字,然后你就可以把beer的名字在文本框内输入为任何内容,只要不空.为了薄脆笔记内容到 beer的笔记值里面,找到textViewDidEndEditing:方法,向如下编辑[objc] view plain copy- (void)textViewDidEndEditing:(UITextView *)textView {      [textView resignFirstResponder];      if ([textView.text length] > 0) {          self.beer.beerDetails.note = textView.text;      }  }  下一步确保用户在View Controller里面改变评价,beer的评价会自动更新.在updateRating里面添加:[objc] view plain copy- (void)updateRating {      self.beer.beerDetails.rating = @(self.ratingControl.rating);  }  当用户在详情页面点击UIImageView,将允许他们添加或者编辑一张图片.一个UIActionSheet 将会展示出来,它将允许用户下哦那个相机胶卷选择照片,或者拍一张新的照片.如果用户想拍照片,你得确保照片已经保存在磁盘上了.不是吧照片保存在Core Data里面(这将导致性能问题),而是保存在用户的文件目录里面.你只需把图片路径保存在CoreData里面.通过实现UIImagePickerControllerDelegate 方法,在照片和图库之间管理互动,你需要在UIImagePickerController里面实现BeerViewController 委派,用来在故事板里面操纵视图.找到imagePickerController:didFinishPickingMediaWithinfo,添加如下代码:[objc] view plain copy- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {      // 1. Grab image and save to disk      UIImage *image = info[UIImagePickerControllerOriginalImage];          // 2. Remove old image if present      if (self.beer.beerDetails.image) {          [ImageSaver deleteImageAtPath:self.beer.beerDetails.image];      }      // 3. Save the image      if ([ImageSaver saveImageToDisk:image andToBeer:self.beer]) {          [self setImageForBeer:image];      }      [picker dismissViewControllerAnimated:YES completion:nil];  }  下面讲解下上面的代码:1.imagePickerController:didFinishPickingMediaWithInfo:间接的传递了用户选择图片的一个参数,,图片是在信息字典里面的,key是UIImagePickerControllerOriginalImage2.如果Beer图像已经包含了一个图片,程序将把它从硬盘删除.因此你并不会把用户的存储占满.3.接着新的图片被保存到硬盘,路径被添加到了BeerDetails 的图片属性里面.打开  ImageSaver 找到saveImageToDisk:andToBeer 看一下  是什么样子.一旦图片被成功保存,将会在UIImageView里面展现出来4.选择器消失.为了使上面的修改器作用,你将修改ImageSaver ,现在你已经创建了Beer 类,你可以取消import行和设置图片路径行的注释.打开ImageSaver.m,修改导入语句如下:[objc] view plain copy#import "ImageSaver.h"  #import "Beer.h"  #import "BeerDetails.h"  现在你需要取消有if语句这行的注释[objc] view plain copyif ([imgData writeToFile:jpgPath atomically:YES]) {          beer.beerDetails.image = path;  }  ImageSaver 类已经做好准备来接受图片了.并且保存图片到手机的文件目录里面.保存路径到BeerDetails 从这里开始用户有两个选择,取消或完成,当你创建一个视图,Beer实体就被创建了,然后插入到managedObjectContext里面。取消则会删除Beer 对象。找到cancelAdd,加入如下代码;[objc] view plain copy- (void)cancelAdd {      [self.beer deleteEntity];      [self.navigationController popViewControllerAnimated:YES];  }  MagicalRecord 提供了一个好的方法来删除实体---从MagicalRecord 里面移出该实体。删除之后用户将返回到beers的主列表。如果用户选择完成,将保存beer 并返回到主列表。找到addNewBeer,它将简单的pop出view controller,返回到列表。当视图消失时将调用viewWillDisapper,然后将轮流调用saveContext现在saveContext 是空的,因此你需要添加代码来保存新的实体。向saveContext:添加如下代码:[objc] view plain copy- (void)saveContext {      [[NSManagedObjectContext defaultContext] saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {          if (success) {              NSLog(@"You successfully saved your context.");          } else if (error) {              NSLog(@"Error saving context: %@", error.description);          }      }];  }  接下来,还有几行代码要做,在 In AppDelegate.m, 里面用 MagicalRecord建立  Core Data堆栈,这将创建一个app全局可用的默认的managedObjectContext  对象。当你创建了 Beer 和BeerDetails 实体,他们就被插入到defaultContext 里面了。MagicalRecord 允许你保存任何你可能是使用saveToPersistentStoreWithCompletion: 的managedObjectContext 。若保存失败完成的块里面讲给你一个NSError。这里你已经添加了一个简单的if/else块来打印出保存defaultContext时发生的问题。你想测试一下结果吗?继续运行你的app,选择+按钮,填满内容,选择完成。这样做之后,在列表的顶部你没有发现新建的Beer,不要急,没问题,你将学会怎样调整问题。你可能发现调试器里面有遗传信息。与你所说的相反,你成功了!  Magical调试器当app启动时,在 Core Data 堆栈启动期间MagicalRecord 打印出信息,这说明Core Data 正在启动。然后创建了defaultContext. 对象。这和我们前文提到的你保存beer 对象的是同一个defaultContext. 当你用MagicalRecord选择完成或者保存时,又会出现一系列Log,当你保存时你将看到如下log信息:1、defaultContext 保存到主线程。2、任何上下文的父类都将保存,以标志1设计。3、最后的log显示MagicalRecord 知道两个对象(Beer 和BeerDetail)都将保存,并且被成功保存。MagicalRecord 为你打印出了很多log,如果你有问题,或者有些事情的表现出乎你的意料,你应该检查日志,来获得有用信息。注意:虽然我不推荐这莫做,如果你一定想看到发生什么情况当取消掉MagicalRecord 的日志打印。你可以在MagicalRecord.h, 的17行吧:[objc] view plain copy#define MR_ENABLE_ACTIVE_RECORD_LOGGING 1  改成[objc] view plain copy#define MR_ENABLE_ACTIVE_RECORD_LOGGING 0  Noch ein Bier, bitte(不会翻译)如果应用程序值得所做的工作,你将需要看到你所添加的beers 。打开MasterViewController.m在顶部导入 Beer.h,和 BeerDetails.h为了得到所有保存在Core Data的Beer,你需要做一些事,viewWillAppear:,里面,在调用 reloadData.之前添加fetch方法。[objc] view plain copy- (void)viewWillAppear:(BOOL)animated {      [super viewWillAppear:animated];      // Check if the user's sort preference has been saved.      ...      [self fetchAllBeers];      [self.tableView reloadData];  }  当视图第一次加载时,或者从查看或添加beer返回时,将获取和加载所有的beers 到列表中。找到fetchAllBeers, 加入下列代码:[objc] view plain copy- (void)fetchAllBeers {      // 1. Get the sort key      NSString *sortKey = [[NSUserDefaults standardUserDefaults] objectForKey:WB_SORT_KEY];      // 2. Determine if it is ascending      BOOL ascending = [sortKey isEqualToString:SORT_KEY_RATING] ? NO : YES;      // 3. Fetch entities with MagicalRecord      self.beers = [[Beer findAllSortedBy:sortKey ascending:ascending] mutableCopy];  }  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:,添加下列代码:[objc] view plain copy- (void)configureCell:(UITableViewCell*)cell atIndex:(NSIndexPath*)indexPath {      // Get current Beer      Beer *beer = self.beers[indexPath.row];      cell.textLabel.text = beer.name;          // Setup AMRatingControl      AMRatingControl *ratingControl;      if (![cell viewWithTag:20]) {          ratingControl = [[AMRatingControl alloc] initWithLocation:CGPointMake(190, 10) emptyImage:[UIImage imageNamed:@"beermug-empty"] solidImage:[UIImage imageNamed:@"beermug-full"] andMaxRating:5];          ratingControl.tag = 20;          ratingControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;          ratingControl.userInteractionEnabled = NO;          [cell addSubview:ratingControl];      } else {          ratingControl = (AMRatingControl*)[cell viewWithTag:20];      }      // Put beer rating in cell      ratingControl.rating = [beer.beerDetails.rating integerValue];  }  现在,再找到 prepareForSegue:sender:, 在if语句里检查如果segue标识符是“editBeer,” 添加:[objc] view plain copyif ([[segue identifier] isEqualToString:@"editBeer"]) {      NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];      Beer *beer = self.beers[indexPath.row];      upcoming.beer = beer;  }  这将把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:, 方法添加如下代码:[objc] view plain copy- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {      if (editingStyle == UITableViewCellEditingStyleDelete) {          Beer *beerToRemove = self.beers[indexPath.row];          // Remove Image from local documents          if (beerToRemove.beerDetails.image) {              [ImageSaver deleteImageAtPath:beerToRemove.beerDetails.image];          }          // Deleting an Entity with MagicalRecord          [beerToRemove deleteEntity];          [self saveContext];          [self.beers removeObjectAtIndex:indexPath.row];          [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];      }  }  记住这里调用了saveContext.方法,你需要添加一些代码来确保删除通过,你已经做过一次了,你能指出怎么做吗?准备。。。开始!添加如下代码来保存上下文[objc] view plain copy// Save ManagedObjectContext using MagicalRecord  [[NSManagedObjectContext defaultContext] saveToPersistentStoreAndWait];  严格来说你没必要知道它什么时候结束,你可以使用MagicalRecord 的其他方式来保存managedObjectContext。把App跑起来,删除一个Beer(使用传统的删除cell的方式)如果你重启App,beer就消失了。你做的很对,保存了我们的更改。这意味着你已经正确的使用了 MagicalRecord。拍拍肩膀,放松下。Demo数据给用户一些初始化的数据,用户就会很容易明白怎么记录自己喜欢的啤酒,这样会更好。在 AppDelegate.m里面导入 Beer.h, BeerDetails.h. 当建立 Core Data堆栈之后加入以下代码:[objc] view plain copy// Setup App with prefilled Beer items.  if (![[NSUserDefaults standardUserDefaults] objectForKey:@"MR_HasPrefilledBeers"]) {      // Create Blond Ale      Beer *blondAle = [Beer createEntity];      blondAle.name  = @"Blond Ale";      blondAle.beerDetails = [BeerDetails createEntity];      blondAle.beerDetails.rating = @4;      [ImageSaver saveImageToDisk:[UIImage imageNamed:@"blond.jpg"] andToBeer:blondAle];        // Create Wheat Beer      Beer *wheatBeer = [Beer createEntity];      wheatBeer.name  = @"Wheat Beer";      wheatBeer.beerDetails = [BeerDetails createEntity];      wheatBeer.beerDetails.rating = @2;      [ImageSaver saveImageToDisk:[UIImage imageNamed:@"wheat.jpg"] andToBeer:wheatBeer];        // Create Pale Lager      Beer *paleLager = [Beer createEntity];      paleLager.name  = @"Pale Lager";      paleLager.beerDetails = [BeerDetails createEntity];      paleLager.beerDetails.rating = @3;      [ImageSaver saveImageToDisk:[UIImage imageNamed:@"pale.jpg"] andToBeer:paleLager];        // Create Stout      Beer *stout = [Beer createEntity];      stout.name  = @"Stout Lager";      stout.beerDetails = [BeerDetails createEntity];      stout.beerDetails.rating = @5;      [ImageSaver saveImageToDisk:[UIImage imageNamed:@"stout.jpg"] andToBeer:stout];        // Save Managed Object Context      [[NSManagedObjectContext defaultContext] saveToPersistentStoreWithCompletion:nil];        // Set User Default to prevent another preload of data on startup.      [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MR_HasPrefilledBeers"];      [[NSUserDefaults standardUserDefaults] synchronize];  }  在本教程的开始你下载的启动ap,包含了4张灰白色的啤酒照片。在这里你只需要创建4种不同的啤酒,然后保存它们。在NSUserDefaults 里面保存个标志,确保应用里面预先填好数据模型当应用程序第一次启动的时候。再次运行应用程序,现在你就可以看到所有的新啤酒了。尝试删除一个,然后重新运行Ap,然后删掉的那个就消失了。如果你想再一次看到那几个啤酒,从设备里面删除应用,重新运行应用就可以了。搜索现在你已经有超过一种的啤酒,可以测试一下搜索的功能,启动Ap已经包含了一个搜索栏,滑动到列表的头部就可以看到。你所需要做的仅仅是添加搜索啤酒的逻辑。之前你使用过MagicalRecord 的一个方法来获取所有种类的啤酒。然后她仅仅简单的返回了所有品种的啤酒,现在你需要在所有啤酒里面检索特殊种类的啤酒。要做到这一点你需要用到谓语动词。之前教程已经讲解了一个使用谓语动词检索的方法。----你能猜出来怎么做吗?逻辑代码在MasterViewController.m 的doSearch 方法里面。[objc] view plain copy- (void)doSearch {      // 1. Get the text from the search bar.      NSString *searchText = self.searchBar.text;      // 2. Do a fetch on the beers that match Predicate criteria.      // In this case, if the name contains the string      self.beers = [[Beer findAllSortedBy:SORT_KEY_NAME ascending:YES withPredicate:[NSPredicate predicateWithFormat:@"name contains[c] %@", searchText] inContext:[NSManagedObjectContext defaultContext]] mutableCopy];      // 3. Reload the table to show the query results.      [self.tableView reloadData];  }  再次运行Ap将啤酒列表页面向下拽,一直到出现搜索栏。在列表栏里面搜索(列表里有的和没有的),你得到想要的结果了吗?从这之后干什么但愿,MagicalRecord 教程能够展示给你使用MagicalRecord 有多么的容易。学会这个样板真的很有用。你在教程里面探索的原理能够帮你开发各种ap,来帮助用户记录他们喜欢的图片,笔记,和评价。多享受啊!你可以下载完整的代码在这个链接,如果你卡在哪里这将很有帮助。如果你想进一步开发这个工程,下面是一些想法:1、在MasterViewController 里面添加“还没创建啤酒”的提示。-----检查并使用MagicalRecord 里面的hasAtLeastOneEntity方法。2、添加消息提示有多少啤酒匹配搜索条件,使用countOfEntitiesWithPredicate: 方法。3、完善数据库重置功能-----查看MagicalRecord里面的truncateAll 方法。4、如果有兴趣打开 MagicalRecordShorthand.h 阅读以下里面的方法是名称----大部分方法的名字都很容易理解,这个头文件应该会给你一些怎么使用MagicalRecord的一些更好的想法。如果你对本教程有任何问题,或者有任何评论,请加入下面的讨论。初次翻译,错误之处还请谅解.  完整例子代码见:http://download.csdn.net/detail/dongtaochen2039/8139455顶5踩0  上一篇tomcat下解决 iOS7.1企业应用"无法安装应用程序 因为证书无效"的问题下一篇IOS后台运行我的同类文章IOS(2)•IOS UIScrollView的自动布局2014-12-05阅读9216•IOS后台运行2014-11-28阅读7100猜你在找iOS开发从入门到精通(Xcode8和Swift3)精通iOS移动开发(Xcode7&Swift2;) 初识Xcode7.0iOS移动开发从入门到精通(Xcode7 & Swift2)iOS8开发技术(Swift版):iOS基础知识精通iOS移动开发(Xcode7&Swift2;):视图与视图控制器undefined reference to stdios_baseInitInitIOS开发报错之Undefined symbols for architecture armv6ios build时Undefined symbols for architecture xxx问题的总结IOS成长之路-Undefined symbols for architecture armv7s解决之道iOS undefined symbols for architecture x86_64 查看评论7楼 qq_32560651 2016-05-23 10:39发表 [回复]楼主辛苦了,翻译的很好啊,学到很多东西呢6楼 南之倩倩 2015-10-16 15:13发表 [回复]setupAutoMigratingCoreDataStack 数据库迁移怎么用?5楼 wjn19910224 2015-10-06 17:51发表 [回复]为什么你的删除会崩,我照着你的打的确不崩呢。4楼 qq_16548849 2015-08-22 22:40发表 [回复]翻译的很好 赞一个 qq :596201463 加个好友3楼 圆咕隆咚的妞妞 2015-07-03 11:39发表 [回复]写的很好~~2楼 Soldier_cy 2015-06-09 16:51发表 [回复]非常感谢1楼 zzking321 2015-02-06 20:23发表 [回复]thx您还没有登录,请[登录]或[注册]* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场核心技术类目全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStack VPN Spark ERP IE10 Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQuery BI HTML5 Spring Apache .NET API HTML SDK IIS Fedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTC coremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech Perl Tornado Ruby Hibernate ThinkPHP HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap个人资料 访问我的空间 DarrenChen 访问:36311次积分:357等级: 排名:千里之外原创:4篇转载:0篇译文:2篇评论:11条文章搜索文章分类java 设计模式(2)IOS(3)文章存档2014年12月(1)2014年11月(1)2014年10月(1)2014年03月(1)2013年04月(2)阅读排行IOS MagicRecord 详解(17341)IOS UIScrollView的自动布局(9209)IOS后台运行(7095)tomcat下解决 iOS7.1企业应用"无法安装应用程序 因为证书无效"的问题(1771)设计模式之桥接模式(376)设计模式之工厂模式(277)评论排行IOS MagicRecord 详解(7)IOS后台运行(2)IOS UIScrollView的自动布局(2)设计模式之工厂模式(0)设计模式之桥接模式(0)tomcat下解决 iOS7.1企业应用"无法安装应用程序 因为证书无效"的问题(0)推荐文章* Chromium扩展(Extension)机制简要介绍和学习计划* Android官方开发文档Training系列课程中文版:APP的内存管理* 程序员,别了校园入了江湖* RxJava 合并组合两个(或多个)Observable数据源* 探索Android软键盘的疑难杂症最新评论IOS MagicRecord 详解qq_32560651: 楼主辛苦了,翻译的很好啊,学到很多东西呢IOS后台运行c3812600: AVPlayerActionAtItemEndAdvance 这句实现不了重复播放, 我通过se...IOS MagicRecord 详解南之倩倩: setupAutoMigratingCoreDataStack 数据库迁移怎么用?IOS MagicRecord 详解wjn19910224: 为什么你的删除会崩,我照着你的打的确不崩呢。IOS MagicRecord 详解qq_16548849: 翻译的很好 赞一个 qq :596201463 加个好友IOS MagicRecord 详解圆咕隆咚的妞妞: 写的很好~~IOS MagicRecord 详解Soldier_cy: 非常感谢IOS后台运行raphae000: 赞 真心好文章IOS MagicRecord 详解zzking321: thxIOS UIScrollView的自动布局DarrenChen: 你的层级改成scrollview->view->label,然后label再用相对于view的bot...公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告|合作伙伴|论坛反馈网站客服杂志客服微博客服webmaster@csdn.net400-600-2320|北京创新乐知信息技术有限公司 版权所有|江苏乐知网络技术有限公司 提供商务支持京 ICP 证 09002463 号|Copyright © 1999-2016, CSDN.NET, All Rights Reserved GongshangLogo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • CoreData是Mac OS 和IOS开发数据持久化和用户数据检索的不可缺少的一部分。为了使API对开发者更容易...
    adrian920阅读 2,590评论 0 3
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,029评论 4 62
  • 何谓罗马帝国呢?这正是一个由尤里乌斯·恺撒绘制蓝图,奥古斯都以此为蓝本建成的一个庞大建筑物。如若把这项工程交给一个...
    会飞的鱼0518阅读 103评论 0 0
  • 你们有经过某个地方,听到某首歌就想起某个情景的情况么?人的回忆和大脑真的很神奇,今天就讲这样一个故事。 我觉得只有...
    a0613515b241阅读 343评论 0 0
  • 今天是军训第四天,我半夜揉着腿,突然觉得必须写点啥。 从山西忻州河曲到广西梧州需要40小时三十分钟,...
    黄小饱阅读 138评论 1 0