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

罗朝辉(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,表示该班的班长。

代码下载:点此下载

=========================================================================

接前半部分

7,创建 NSArrayController,关联对象
现在回到 xib 中来,选中 StudentView.xib,设置StudentView 的 File's Owner 的类为 StudentViewController;使用 Control-Drag 将 File's Owner 的 view 指向 custom view。

向其中拖入两个 NSArrayController:ClassPopup 和 Students。
设置 ClassPopup 的 Object Controller Mode 为 Entity Name,实体名为:ClassEntity,并勾选 Prepare Content。
设置 Students 的 Object Controller Mode 为 Entity Name,实体名为:StudentEntity,并勾选 Prepare Content。

上面的这些操作,ClassPopup ArrayController 管理 ClassEntity 的数据,Students ArrayController 管理 StudentEntity 的数据,后面我们就要将控件与这些 ArrayController 绑定起来。下面我们将这两个 NSArrayController 的 ManagedObjectContext 参数与 ManagedViewController(File's Owner) 中的 managedObjectContext 绑定起来,这样 NSDocuments 的 NSManagedObjectContext 就作用到的 ArrayController 中来了。下面只演示了 ClassPopup,请自行完成 Students 的绑定:

前面我们在 ManagedViewController 创建了一个 IBOutlet contentArrayController,现在是将它关联的时候了,使用 Control-Drag 将 File's Owner 的 contentArrayController 关联到 Students。

重复上面的过程,选中 ClassView.xib,将 File's Owner 的类为 ClassViewController,并将其 view 指向 custom view。
向其中拖入三个 NSArrayController:Classes,MonitorPopup 和 Students。
设置 Classes 的 Object Controller Mode 为 Entity Name,实体名为:ClassEntity,并勾选 Prepare Content。
将 Classes 的 ManagedObjectContext 参数与 ManagedViewController(File's Owner) 中的 managedObjectContext 绑定起来。
注意:这里没有对 MonitorPopup 和 Students 进行修改。
使用 Control-Drag 将 File's Owner 的 contentArrayController 关联到 Classes。

将 Students 和 MonitorPopup 的 Content set 绑定到 Classes 的  Model key path: students,表示这两个 ArrayController  是管理对应 ClassEntity 的 students 的数据。

至此,模型, ArrayController 都准备好了,下面我们将控件绑定到这些对象上。上面已经够繁琐的了,下面我们得更加仔细,很容易出错的。

选中 StudentView.xib,展开 Custom View 中的 TableView,直到我们看到名称和班级两个 Table Column。
选中名称列,将其 value 绑定到 Students,model key path 为:name,表明第一列显示学生的名称;
选择班级列,注意这一列是popup button cell,
将其 Content 绑定到 ClassPopup;
将其 ContentValues 绑定到 ClassPopup,model key path 为:name,表明第二列的选项为班级的名称;
将其 Selected Object 绑定到 Students,model key path 为:inClass;表明将学生添加为选中班级的一员;

选中 + button,使用 Control+Drag将其托拽到 Students 上,选择 add: 动作关联;
选中 - button,使用 Control+Drag将其托拽到 Students 上,选择 remove: 动作关联;
选中 - button,将其 Eanbled 绑定到 Students, ctroller key 为:canRemove;
以上操作是将添加,删除学生的操作直接与 Students ArrayController 绑定,无需编写一点儿代码!

选中 ClassView.xib
展开 Custom View 中的班级表,,直到我们看到班级 Table Column:选择班级列,将其 value 绑定到 Classes,model key path 为:name,表明这一列显示班级的名称;
选中 Box,将其 Title 绑定到 Classed,model key path 为:name,并设置下方的 No Selection Placeholder 为:No Selection,Null Placeholder 为:Unnamed Class。 表明 box 显示的信息为选中班级的信息,如果没有选中任何班级,则显示 No Selection。

展开 Box
选中 Pop up button
将其 Content 绑定到 MonitorPopup;
将其 ContentValues 绑定到 MonitorPopup,model key path 为:name,表明其选项为班级中的学生的名称;
将其 Selected Object 绑定到 Classes,model key path 为:monitor;表明将选中的学生当作该班级的班长;

展开学生 tabel view,直到我们看到学生这个 Table Column。
选择学生列,将其 Value 绑定到 Students,Model key path 为:name,表明学生列表显示该班级中所有学生的名称。

选中 + button,使用 Control+Drag 将其托拽到 Classes 上,选择 add: 动作关联;
选中 - button,使用 Control+Drag 将其托拽到 Classes 上,选择 remove: 动作关联;
选中 - button,将其 Eanbled 绑定到 Classes, ctroller key 为:canRemove;
以上操作是将添加,删除班级的操作直接与 Classes ArrayController 绑定。

至此,绑定也大功告成,如果你的程序运行不正确,多半是这地方的关联与绑定错了,请回到这部分,仔细检查每一项。

8,显示,切换 view。
现在到了设置主界面的时候,修改 MyDocument.h 中的代码如下:

  1. #import <Cocoa/Cocoa.h>
  2. @class ManagedViewController;
  3. @interface MyDocument : NSPersistentDocument {
  4. @private
  5. NSBox *         box;
  6. NSPopUpButton * popup;
  7. NSMutableArray *viewControllers;
  8. NSInteger       currentIndex;
  9. }
  10. @property (nonatomic, retain) IBOutlet NSBox *          box;
  11. @property (nonatomic, retain) IBOutlet NSPopUpButton *  popup;
  12. - (IBAction) changeViewController:(id)sender;
  13. - (void) displayViewController:(ManagedViewController *)mvc;
  14. @end

修改 MyDocument.m  中的代码如下:

  1. #import "MyDocument.h"
  2. #import "ClassViewController.h"
  3. #import "StudentViewController.h"
  4. @implementation MyDocument
  5. @synthesize popup;
  6. @synthesize box;
  7. - (id)init
  8. {
  9. self = [super init];
  10. if (self) {
  11. // create view controllers
  12. //
  13. viewControllers = [[NSMutableArray alloc] init];
  14. ManagedViewController * mvc;
  15. mvc = [[ClassViewController alloc] init];
  16. [mvc setManagedObjectContext:[self managedObjectContext]];
  17. [viewControllers addObject:mvc];
  18. [mvc release];
  19. mvc = [[StudentViewController alloc] init];
  20. [mvc setManagedObjectContext:[self managedObjectContext]];
  21. [viewControllers addObject:mvc];
  22. [mvc release];
  23. }
  24. return self;
  25. }
  26. - (void) dealloc
  27. {
  28. self.box = nil;
  29. self.popup = nil;
  30. [viewControllers release];
  31. [super dealloc];
  32. }
  33. - (NSString *)windowNibName
  34. {
  35. // Override returning the nib file name of the document
  36. // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
  37. return @"MyDocument";
  38. }
  39. - (void)windowControllerDidLoadNib:(NSWindowController *)aController
  40. {
  41. [super windowControllerDidLoadNib:aController];
  42. // init popup
  43. //
  44. NSMenu *menu = [popup menu];
  45. NSInteger itemCount = [viewControllers count];
  46. for (NSInteger i = 0; i < itemCount; i++) {
  47. NSViewController *vc = [viewControllers objectAtIndex:i];
  48. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[vc title]
  49. action:@selector(changeViewController:)
  50. keyEquivalent:@""];
  51. [item setTag:i];
  52. [menu addItem:item];
  53. [item release];
  54. }
  55. // display the first controller
  56. //
  57. currentIndex = 0;
  58. [self displayViewController:[viewControllers objectAtIndex:currentIndex]];
  59. [popup selectItemAtIndex:currentIndex];
  60. }
  61. #pragma mark -
  62. #pragma mark Change Views
  63. - (IBAction) changeViewController:(id)sender
  64. {
  65. NSInteger tag = [sender tag];
  66. if (tag == currentIndex) {
  67. return;
  68. }
  69. currentIndex = tag;
  70. ManagedViewController *mvc = [viewControllers objectAtIndex:currentIndex];
  71. [self displayViewController:mvc];
  72. }
  73. - (void) displayViewController:(ManagedViewController *)mvc
  74. {
  75. NSWindow *window = [box window];
  76. BOOL ended = [window makeFirstResponder:window];
  77. if (!ended) {
  78. NSBeep();
  79. return;
  80. }
  81. NSView *mvcView = [mvc view];
  82. // Adjust window's size and position
  83. //
  84. NSSize currentSize      = [[box contentView] frame].size;
  85. NSSize newSize          =  [mvcView frame].size;
  86. float deltaWidth        = newSize.width - currentSize.width;
  87. float deltaHeight       = newSize.height - currentSize.height;
  88. NSRect windowFrame      = [window frame];
  89. windowFrame.size.width  += deltaWidth;
  90. windowFrame.size.height += deltaHeight;
  91. windowFrame.origin.y    -= deltaHeight;
  92. [box setContentView:nil];
  93. [window setFrame:windowFrame display:YES animate:YES];
  94. [box setContentView:mvcView];
  95. // add viewController to the responder-chain
  96. //
  97. [mvcView setNextResponder:mvc];
  98. [mvc setNextResponder:box];
  99. }
  100. @end

在 MyDocument 中,我们创建了两个 ManagedViewController,并将 managedObjectContext 传入其中。这两个ViewController分别代表班级与学生两个界面,然后通过 popup button 的选择在他们之间切换显示;在 displayViewController 中,我们还根据当前界面的大小来调整主界面的大小。这需要我们设置主界面中 box 的自动大小。打开 MyDocument.xib,作如下设置:

然后,使用 Control+Drag,将 File's Owner的 popup 和 popup button相联,box 与 box相联,并将 popup button 的 action 设置为 File's Owner 的 - (IBAction) changeViewController:(id)sender。

至此,所有的工作都完成了。编译运行程序,如果不出意外的话,我们应该可以添加学生,班级,并设置学生的班级,班级的班长等信息了。

最新文章

  1. 吃透Javascript数组操作的正确姿势—再读《Js高程》
  2. SPI
  3. thinkphp计划任务使用cronRun
  4. android studio 修改成自己jks(keystore)签名文件
  5. ubuntu下取代ping的好工具tcpping
  6. Scala Collection简介
  7. Java初学之华容道游戏
  8. RaidoGroup+RadioButton模拟android下拉框弹出List
  9. 【M9】利用destructors避免泄漏资源
  10. QVector&amp;lt;QString&amp;gt; 显示器里面的动态数组元素QString和char *转变
  11. HBase集群安装
  12. php处理表单中的复选框问题以及js实现全选
  13. .net到Java那些事儿--structs做了那些事(二)
  14. Spark-1.6.0之Application运行信息记录器JobProgressListener
  15. HTTP,RFC自学心得
  16. Starting zookeeper ... already running as process 1805错误
  17. webpack打包去掉console.log打印与debugger调试
  18. R语言函数总结(转)
  19. 【贪心策略】USACO 越野跑
  20. 20155332 补交ch12课下作业

热门文章

  1. CMD命令简介
  2. 运维Python面试题
  3. kubernetes大概的工作原理
  4. 07 JVM 是如何实现反射的
  5. Log4j官方文档翻译(三、配置)
  6. FreeBSD 用kgdb调试kernel dump文件
  7. hihoCoder 1467 2-SAT&#183;hihoCoder音乐节(2-SAT模版)
  8. 外星千足虫(bzoj 1923)
  9. HDOJ Important Sisters
  10. 【HDOJ5532】Almost Sorted Array(签到)