深入浅出 Cocoa 之 Core Data(3)- 使用绑定

罗朝辉(http://blog.csdn.net/kesalin)

CC 许可,转载请注明出处

前面讲解了 Core Data 的框架,并完全手动编写代码演示了 Core Data 的运作过程。下面我们来演示如何结合 XCode 强大的可视化编辑以及 Cocoa 键值编码,绑定机制来使用 Core Data。有了上面提到的哪些利器,在这个示例中,我们无需编写 NSManagedObjectModel 代码,也无需编写 NSManagedObjectContext,工程模版在背后为我们做了这些事情。

今天要完成的这个示例,有两个 Entity:StudentEntity 与 ClassEntity,各自有一个名为 name 的 Attribute。其中 StudentEntity 通过一个名为 inClass 的 relationship 与 ClassEntity关联,而 ClassEntity 也有一个名为 students 的 relationship 与 StudentEntity 关联,这是一个一对多的关系。此外 ClassEntity 还有一个名为 monitor 的 relationship 关联到 StudentEntity,表示该班的班长。

代码下载:点此下载

最终的效果图如下:

下面我们一步一步来完成这个示例:
1,创建工程:
创建一个 Cocoa Application,工程名为:MacCoreData,并勾选 Create Document-Based Application 和 Use Core Data,在这里要用到 Core Data 和 Document 工程模版,以简化代码的编写。

2,分类文件:
在 MacCoreData 下新建 Src 和 Res 两个 Group,并将 MyDocument.h 和 MyDocument 拖到 Src 下,将其他 xib 和 xcdatamodeld 拖到 Res 中。将文件分类是个好习惯,尤其是对大项目来说。后面请自觉将文件分类~~

3,创建 Entity:
在工程中,我们可以看到名为 MyDocument.xcdatamodeld 的文件,其后缀表明这是一个 core data model文件,框架就是读取该模型文件生成模型的。下面我们选中这个文件,向其中添加两个实体。点击下方的 Add Entity 增加两个新 Entity: ClassEntity 和 StudentEntity。

向 StudentEntity 中添加名为 name 的 string 类型的 Attribute,并设置其 Default Value 为学生甲,去除 Optional 前勾选状态;
向 ClassEntity 中添加名为 name 的 string 类型的 Attribute,并设置其 Default Value 为XX班,去除 Optional 前勾选状态;
选项 Optional 是表示该  Attribute 可选与否的,在这里 name 都是必须的。

向 StudentEntity 中添加名为 inClass 指向 ClassEntity 的 Relationship,其 Inverse 栏要等 ClassEntity 添加了反向关系才能选择,后面回提到;
向 ClassEntity 中添加名为 students 指向 StudentEntity 的 Relationship,其 Inverse 栏选择 inClass,表明这是一个双向关系,勾选 To-Many Relationship,因为一个班级可以有多名学生,这是一对多关系。设定之后,我们可以可以将 StudentEntity 的 inClass 关系的 Inverse 设置为 students了。
再向 ClassEntity 中添加名为 monitor 指向 StudentEntity 的 Relationship,表示该班的班长。

4,生成 NSManagedObject 类:
选中 StudentEntity,然后点击菜单 File-> New -> New file…,添加 Core Data -> NSManagerObject subclass, XCode 就会自动为我们生成 StudentEntity.h 和 StudentEntity.m 文件,记得将这两个文件拖放到 Src Group 下。下面我们来看看这两个文件中有什么内容:
StudentEntity.h

  1. #import <Foundation/Foundation.h>
  2. #import <CoreData/CoreData.h>
  3. @class ClassEntity;
  4. @interface StudentEntity : NSManagedObject {
  5. @private
  6. }
  7. @property (nonatomic, retain) NSString * name;
  8. @property (nonatomic, retain) ClassEntity * inClass;
  9. @end

StudentEntity.m

  1. #import "StudentEntity.h"
  2. #import "ClassEntity.h"
  3. @implementation StudentEntity
  4. @dynamic name;
  5. @dynamic inClass;
  6. @end

在前面手动代码的示例中,我们是自己编写 Run NSManagedObject的代码,而现在,XCode 已经根据模型文件的描述,自动为我们生成了,方便吧。有时候自动生成的代码不一定满足我们的需要,我们就得对代码进行修改,比如对 ClassEntity 来说,班长只能是其 students 中的一员,如果我们在 students 中移除了班长那个学生,那么该班级的班长就应该置空。

选中 ClassEntity,重复上面的步骤,自动生成 ClassEntity.h 和 ClassEntity.m,下面我们根据需求来修改 ClassEntity.m。
在 - (void)removeStudentsObject:(StudentEntity *)value 的开头添加如下代码:

  1. if (value == [self monitor])
  2. [self setMonitor:nil];

在 - (void)removeStudents:(NSSet *)value 的开头添加如下代码:

  1. if ([value containsObject:[self monitor]])
  2. [self setMonitor:nil];

这样当我们在 students 中删除一个学生时,就会检测该学生是不是班长,如果是,就将该班的班长置空。

5,下面来生成 UI 界面:
在这里,我们是通过切换 view 的方法来显现学生与班级两个界面,因此我们需要主界面,班级以及学生共三个界面。

向 MyDocument.xib 中添加如下一个 popup button 和一个 NSBox。并删除 popup 控件中的 menu item,因为我们要通过代码来添加班级,学生项的。

然后在 Res 中添加两个新 Empty xib 文件:StudentView.xib 和 ClassView.xib,分别向这两个 xib 文件中拖入一个 Custom View,然后在这个 view 添加相关控件构成 UI。记得设置 ClassView 中两个 tableView 的列数为 1,拖入一个 PopupButtonCell 到 StudentView 中班级那一列。效果如下:

6,添加 ViewController:
下面我们创建 ViewController 来在程序中转载 xib 文件,显示和切换 view。为了便于切换 view,我们创建一个继承自 NSViewController 的名为:ManagedViewController的类(记得不要创建该类对应的 xib 文件!创建一个 NSObject子类,然后修改其父类为 NSViewController),然后让 StudentViewController 和 ClassViewController 从它继承。ManagedViewController 类的代码如下:
ManagedViewController.h

  1. #import <Cocoa/Cocoa.h>
  2. @interface ManagedViewController : NSViewController {
  3. @private
  4. NSManagedObjectContext * managedObjectContext;
  5. NSArrayController * contentArrayController;
  6. }
  7. @property (nonatomic, retain) NSManagedObjectContext * managedObjectContext;
  8. @property (nonatomic, retain) IBOutlet NSArrayController *contentArrayController;
  9. @end

ManagedViewController.m

  1. #import "ManagedViewController.h"
  2. @implementation ManagedViewController
  3. @synthesize managedObjectContext;
  4. @synthesize contentArrayController;
  5. - (void)dealloc
  6. {
  7. self.contentArrayController = nil;
  8. self.managedObjectContext = nil;
  9. [super dealloc];
  10. }
  11. // deal with "Delete" key event.
  12. //
  13. - (void) keyDown:(NSEvent *)theEvent
  14. {
  15. if (contentArrayController) {
  16. if ([theEvent keyCode] == 51) {
  17. [contentArrayController remove:nil];
  18. }
  19. else {
  20. [super keyDown:theEvent];
  21. }
  22. }
  23. else {
  24. [super keyDown:theEvent];
  25. }
  26. }
  27. @end

在上面代码中,我们有一个 NSManagedObjectContext * managedObjectContext 指针,它指向 MyDocument 框架中的NSManagedObjectContext对象,后面我们会说到,至于 NSArrayController * contentArrayController,它是一个 IBOutlet,将与xib 中创建的 NSArrayController关联,后面也会说到。在这里引入 contentArrayController 是为了让 delete 能够删除记录。

ClassViewController 类的代码如下:

  1. #import "ManagedViewController.h"
  2. @interface ClassViewController : ManagedViewController {
  3. @private
  4. }
  5. @end
  6. #import "ClassViewController.h"
  7. @implementation ClassViewController
  8. - (id)init
  9. {
  10. self = [super initWithNibName:@"ClassView" bundle:nil];
  11. if (self) {
  12. [self setTitle:@"班级"];
  13. }
  14. return self;
  15. }
  16. - (void)dealloc
  17. {
  18. [super dealloc];
  19. }
  20. @end

StudentViewController 类的代码如下:

  1. #import "ManagedViewController.h"
  2. @interface StudentViewController : ManagedViewController {
  3. @private
  4. }
  5. @end
  6. #import "StudentViewController.h"
  7. @implementation StudentViewController
  8. - (id)init
  9. {
  10. self = [super initWithNibName:@"StudentView" bundle:nil];
  11. if (self) {
  12. [self setTitle:@"学生"];
  13. }
  14. return self;
  15. }
  16. - (void)dealloc
  17. {
  18. [super dealloc];
  19. }
  20. @end

在这两个子类中,我们在 init 方法中载入 xib 文件,然后设置其 title。

深入浅出 Cocoa 之 Core Data(3)- 使用绑定的更多相关文章

  1. 深入浅出 Cocoa 之 Core Data(4)- 使用绑定

    深入浅出 Cocoa 之 Core Data(4)- 使用绑定 罗朝辉(http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 前面讲解了 Core Data 的框架, ...

  2. 深入浅出 Cocoa 之 Core Data(1)- 框架详解

    深入浅出 Cocoa 之 Core Data(1)- 框架详解 罗朝辉(http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 Core data 是 Cocoa 中处 ...

  3. 深入浅出 Cocoa 之 Core Data(2)- 手动编写代码

    深入浅出 Cocoa 之 Core Data(2)- 代码示例 罗朝辉(http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 前面详细讲解了 Core Data 的框 ...

  4. [Cocoa]深入浅出 Cocoa 之 Core Data(1)- 框架详解

    Core data 是 Cocoa 中处理数据,绑定数据的关键特性,其重要性不言而喻,但也比较复杂.Core Data 相关的类比较多,初学者往往不太容易弄懂.计划用三个教程来讲解这一部分: 框架详解 ...

  5. Cocoa 之 Core Data(2)- 代码示例

    前面详 细讲解了 Core Data 的框架以及设计的类,下面我们来讲解一个完全手动编写代码 使用这些类的示例,这个例子来自 苹果官方示例.在这个例子里面,我们打算做这样一件事 情:记录程序运行记录( ...

  6. 《驾驭Core Data》 第一章 Core Data概述

    <驾驭Core Data>系列教程综合了<Core Data for iOS>,<Learning Core Data for iOS>,<Core Data ...

  7. obj-c编程15[Cocoa实例04]:基于Core Data的多文档程序示例[未完待续]

    上一个例子我们使用的模式数据实际上是基于一个Person数组,现在我们看一下如何使用Cocoa中的Core Data框架支持,几乎不用写一行代码,完成模式数据的建立. 我们这里模式的元素使用的是Car ...

  8. [深入浅出Cocoa]iOS网络编程之Socket

    http://blog.csdn.net/kesalin/article/details/8798039 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   [深入浅出Co ...

  9. [Cocoa]深入浅出Cocoa之Bonjour网络编程

    本文转载至 http://www.cnblogs.com/kesalin/archive/2011/09/15/cocoa_bonjour.html   深入浅出Cocoa之Bonjour网络编程 罗 ...

随机推荐

  1. ogre3D学习基础18 -- 材质的使用与脚本的简单书写

    这一节以基础16为基础,练习材质的使用. 第一,看看框架 //material #include "ExampleApplication.h" class TutorialAppl ...

  2. 解决pymysql不能实时查询最新的数据

    #在网上查询到的原因为: InnoDB 的默认隔离级别.它可以防止任何被查询的行被其他事务更改,从而阻止不可重复的读取,而不是 幻读取.它使用中度严格的锁定策略,以便事务内的所有查询都会查看同一快照中 ...

  3. c语言入门-01

    当我们学c语言我们学些什么. [1]编译机制 当我们写好c的代码,生产了程序,这中间到底做了些什么? 这个就是c语言的编译过程 我们分别来解析这上面的过程. 我们写出我们第一个c程序. #includ ...

  4. 看似不是dfs的dfs HDU-1455

    Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  5. Leetcode 594.最长和谐子序列

    最长和谐子序列 和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1. 现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度. 示例 1: 输入: [1,3,2,2,5 ...

  6. @inerface的11条规范写法

    总结一些interface声明时的规范,相关宏的介绍,定义方法时有用的修饰符,编写注释的规范,最终写出一个合格的头文件. 1.读写权限 1.1实例变量的@public,@protected,@priv ...

  7. Pointcut is not well-formed: expecting 'name pattern' at character position 53

    报错内容: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataso ...

  8. Arcengine 基本操作(待更新)

    /// <summary> /// 删除fieldName属性值为1的弧段 /// </summary> /// <param name="fieldName& ...

  9. mysql错误之2014

    error:2014 Commands out of sync; you can't run this command now 这个错误号我也真是醉了. 一直纠结于为什么存储过程执行完,commit操 ...

  10. bzoj 3704 昊昊的机油之GRST 贪心dp,思维

    昊昊的机油之GRST Time Limit: 10 Sec  Memory Limit: 1024 MBSubmit: 80  Solved: 33[Submit][Status][Discuss] ...