深刻淺出 Cocoa 之 Core Data(4)- 使用綁定

深刻淺出 Cocoa 之 Core Data(4)- 使用綁定mvc

羅朝輝(http://blog.csdn.net/kesalin)app

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,表示該班的班長。ide

代碼下載:點此下載oop

=========================================================================ui

接前半部分this

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 的綁定:
atom

前面咱們在 ManagedViewController 建立了一個 IBOutlet contentArrayController,如今是將它關聯的時候了,使用 Control-Drag 將 File's Owner 的 contentArrayController 關聯到 Students。spa

重複上面的過程,選中 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.   
  3. @class ManagedViewController;  
  4.   
  5. @interface MyDocument : NSPersistentDocument {  
  6. @private  
  7.     NSBox *         box;  
  8.     NSPopUpButton * popup;  
  9.       
  10.     NSMutableArray *viewControllers;  
  11.     NSInteger       currentIndex;  
  12. }  
  13.   
  14. @property (nonatomic, retain) IBOutlet NSBox *          box;  
  15. @property (nonatomic, retain) IBOutlet NSPopUpButton *  popup;  
  16.   
  17. - (IBAction) changeViewController:(id)sender;  
  18. - (void) displayViewController:(ManagedViewController *)mvc;  
  19.   
  20. @end  


修改 MyDocument.m  中的代碼以下:

  1. #import "MyDocument.h"  
  2. #import "ClassViewController.h"  
  3. #import "StudentViewController.h"  
  4.   
  5. @implementation MyDocument  
  6.   
  7. @synthesize popup;  
  8. @synthesize box;  
  9.   
  10. - (id)init  
  11. {  
  12.     self = [super init];  
  13.     if (self) {  
  14.         // create view controllers  
  15.         //  
  16.         viewControllers = [[NSMutableArray alloc] init];  
  17.           
  18.         ManagedViewController * mvc;  
  19.         mvc = [[ClassViewController alloc] init];  
  20.         [mvc setManagedObjectContext:[self managedObjectContext]];  
  21.         [viewControllers addObject:mvc];  
  22.         [mvc release];  
  23.           
  24.         mvc = [[StudentViewController alloc] init];  
  25.         [mvc setManagedObjectContext:[self managedObjectContext]];  
  26.         [viewControllers addObject:mvc];  
  27.         [mvc release];  
  28.     }  
  29.     return self;  
  30. }  
  31.   
  32. - (void) dealloc  
  33. {  
  34.     self.box = nil;  
  35.     self.popup = nil;  
  36.     [viewControllers release];  
  37.       
  38.     [super dealloc];  
  39. }  
  40.   
  41. - (NSString *)windowNibName  
  42. {  
  43.     // Override returning the nib file name of the document  
  44.     // 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.  
  45.     return @"MyDocument";  
  46. }  
  47.   
  48. - (void)windowControllerDidLoadNib:(NSWindowController *)aController  
  49. {  
  50.     [super windowControllerDidLoadNib:aController];  
  51.   
  52.     // init popup  
  53.     //  
  54.     NSMenu *menu = [popup menu];  
  55.     NSInteger itemCount = [viewControllers count];  
  56.       
  57.     for (NSInteger i = 0; i < itemCount; i++) {  
  58.         NSViewController *vc = [viewControllers objectAtIndex:i];  
  59.         NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[vc title]  
  60.                                                       action:@selector(changeViewController:)  
  61.                                                keyEquivalent:@""];  
  62.         [item setTag:i];  
  63.         [menu addItem:item];  
  64.         [item release];  
  65.     }  
  66.       
  67.     // display the first controller  
  68.     //  
  69.     currentIndex = 0;  
  70.     [self displayViewController:[viewControllers objectAtIndex:currentIndex]];  
  71.     [popup selectItemAtIndex:currentIndex];  
  72. }  
  73.   
  74. #pragma mark -  
  75. #pragma mark Change Views  
  76.   
  77. - (IBAction) changeViewController:(id)sender  
  78. {  
  79.     NSInteger tag = [sender tag];  
  80.     if (tag == currentIndex) {  
  81.         return;  
  82.     }  
  83.       
  84.     currentIndex = tag;  
  85.     ManagedViewController *mvc = [viewControllers objectAtIndex:currentIndex];  
  86.     [self displayViewController:mvc];  
  87. }  
  88.   
  89. - (void) displayViewController:(ManagedViewController *)mvc  
  90. {  
  91.     NSWindow *window = [box window];  
  92.     BOOL ended = [window makeFirstResponder:window];  
  93.     if (!ended) {  
  94.         NSBeep();  
  95.         return;  
  96.     }  
  97.       
  98.     NSView *mvcView = [mvc view];  
  99.       
  100.     // Adjust window's size and position  
  101.     //  
  102.     NSSize currentSize      = [[box contentView] frame].size;  
  103.     NSSize newSize          =  [mvcView frame].size;  
  104.     float deltaWidth        = newSize.width - currentSize.width;  
  105.     float deltaHeight       = newSize.height - currentSize.height;  
  106.       
  107.     NSRect windowFrame      = [window frame];  
  108.     windowFrame.size.width  += deltaWidth;  
  109.     windowFrame.size.height += deltaHeight;  
  110.     windowFrame.origin.y    -= deltaHeight;  
  111.       
  112.     [box setContentView:nil];  
  113.     [window setFrame:windowFrame display:YES animate:YES];  
  114.       
  115.     [box setContentView:mvcView];  
  116.       
  117.     // add viewController to the responder-chain  
  118.     //  
  119.     [mvcView setNextResponder:mvc];  
  120.     [mvc setNextResponder:box];  
  121. }  
  122.   
  123. @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。至此,全部的工做都完成了。編譯運行程序,若是不出意外的話,咱們應該能夠添加學生,班級,並設置學生的班級,班級的班長等信息了。

相關文章
相關標籤/搜索