今天要完成的这个示例,有两个 Entity:StudentEntity 与 ClassEntity,各自有一个名为 name 的Attribute 其中 StudentEntity 通过一个名为 inClass 的 relationship 与 ClassEntity关联,而 ClassEntity 也有一个名为 students 的 relationship 与 Entity:StudentEntity 关联,这是一个一对多的关系。此外 ClassEntity 还有一个名为 monitor 的 relationship 关联到 StudentEntity,代表该班的班长。
代码下载:点击下载
最终的效果图如下:
StudentEntity.h
#import <CoreData/CoreData.h>
@class ClassEntity;
@interface StudentEntity : NSManagedObject {
@private
}
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) ClassEntity * inClass;
@end
StudentEntity.m
#import "ClassEntity.h"
@implementation StudentEntity
@dynamic name;
@dynamic inClass;
@end
[self setMonitor:nil];
[self setMonitor:nil];
5,下面来生成 UI 界面:
@interface ManagedViewController : NSViewController {
@private
NSManagedObjectContext * managedObjectContext;
NSArrayController * contentArrayController;
}
@property (nonatomic, retain) NSManagedObjectContext * managedObjectContext;
@property (nonatomic, retain) IBOutlet NSArrayController *contentArrayController;
@end
ManagedViewController.h
@implementation ManagedViewController
@synthesize managedObjectContext;
@synthesize contentArrayController;
- (void)dealloc
{
self.contentArrayController = nil;
self.managedObjectContext = nil;
[super dealloc];
}
// deal with "Delete" key event.
//
- (void) keyDown:(NSEvent *)theEvent
{
if (contentArrayController) {
if ([theEvent keyCode] == 51) {
[contentArrayController remove:nil];
}
else {
[super keyDown:theEvent];
}
}
else {
[super keyDown:theEvent];
}
}
@end
@interface ClassViewController : ManagedViewController {
@private
}
@end
@implementation ClassViewController
- (id)init
{
self = [super initWithNibName:@"ClassView" bundle:nil];
if (self) {
[self setTitle:@"班级"];
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
@end
@interface StudentViewController : ManagedViewController {
@private
}
@end
@implementation StudentViewController
- (id)init
{
self = [super initWithNibName:@"StudentView" bundle:nil];
if (self) {
[self setTitle:@"学生"];
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
@end
注意:这里没有对 MonitorPopup 和 Students 进行修改。
使用 Control-Drag 将 File's Owner 的 contentArrayController 关联到 Classes。
至此,模型, ArrayController 都准备好了,下面我们将控件绑定到这些对象上。上面已经够繁琐的了,下面我们得更加仔细,很容易出错的。
选择班级列,注意这一列是popup button cell,
选中 + button,使用 Control+Drag将其托拽到 Students 上,选择 add: 动作关联;
以上操作是将添加,删除班级的操作直接与 Classes ArrayController 绑定。
@class ManagedViewController;
@interface MyDocument : NSPersistentDocument {
@private
NSBox * box;
NSPopUpButton * popup;
NSMutableArray *viewControllers;
NSInteger currentIndex;
}
@property (nonatomic, retain) IBOutlet NSBox * box;
@property (nonatomic, retain) IBOutlet NSPopUpButton * popup;
- (IBAction) changeViewController:(id)sender;
- (void) displayViewController:(ManagedViewController *)mvc;
@end
修改 MyDocument.m 中的代码如下:
#import "ClassViewController.h"
#import "StudentViewController.h"
@implementation MyDocument
@synthesize popup;
@synthesize box;
- (id)init
{
self = [super init];
if (self) {
// create view controllers
//
viewControllers = [[NSMutableArray alloc] init];
ManagedViewController * mvc;
mvc = [[ClassViewController alloc] init];
[mvc setManagedObjectContext:[self managedObjectContext]];
[viewControllers addObject:mvc];
[mvc release];
mvc = [[StudentViewController alloc] init];
[mvc setManagedObjectContext:[self managedObjectContext]];
[viewControllers addObject:mvc];
[mvc release];
}
return self;
}
- (void) dealloc
{
self.box = nil;
self.popup = nil;
[viewControllers release];
[super dealloc];
}
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// 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.
return @"MyDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
// init popup
//
NSMenu *menu = [popup menu];
NSInteger itemCount = [viewControllers count];
for (NSInteger i = 0; i < itemCount; i++) {
NSViewController *vc = [viewControllers objectAtIndex:i];
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[vc title]
action:@selector(changeViewController:)
keyEquivalent:@""];
[item setTag:i];
[menu addItem:item];
[item release];
}
// display the first controller
//
currentIndex = 0;
[self displayViewController:[viewControllers objectAtIndex:currentIndex]];
[popup selectItemAtIndex:currentIndex];
}
#pragma mark -
#pragma mark Change Views
- (IBAction) changeViewController:(id)sender
{
NSInteger tag = [sender tag];
if (tag == currentIndex) {
return;
}
currentIndex = tag;
ManagedViewController *mvc = [viewControllers objectAtIndex:currentIndex];
[self displayViewController:mvc];
}
- (void) displayViewController:(ManagedViewController *)mvc
{
NSWindow *window = [box window];
BOOL ended = [window makeFirstResponder:window];
if (!ended) {
NSBeep();
return;
}
NSView *mvcView = [mvc view];
// Adjust window's size and position
//
NSSize currentSize = [[box contentView] frame].size;
NSSize newSize = [mvcView frame].size;
float deltaWidth = newSize.width - currentSize.width;
float deltaHeight = newSize.height - currentSize.height;
NSRect windowFrame = [window frame];
windowFrame.size.width += deltaWidth;
windowFrame.size.height += deltaHeight;
windowFrame.origin.y -= deltaHeight;
[box setContentView:nil];
[window setFrame:windowFrame display:YES animate:YES];
[box setContentView:mvcView];
// add viewController to the responder-chain
//
[mvcView setNextResponder:mvc];
[mvc setNextResponder:box];
}
@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。
至此,所有的工作都完成了。编译运行程序,如果不出意外的话,我们应该可以添加学生,班级,并设置学生的班级,班级的班长等信息了。