obj-c編程15[Cocoa實例03]:MVC以及歸檔化示例
前麵的博文裏介紹了歸檔和解檔,這裏我們把它實際應用到一個簡單的代碼中去,將它作為一個多文檔應用程序的打開和保存的背後支持。另外這裏介紹一下MVC思想,這個在任何語言裏都會有,它是一種設計思想,主要可以概括為一個程序由3部分組成:
1 模式:是程序的數據支持;
2 視圖:是程序的表示支持;
3 控製:連接模式和視圖,將程序構為一個整體;
Cocoa框架中對MVC提供了非常好的支持,你隻需要寫很少的代碼就可以完成一個程序的MVC綁定了。下麵的例子中,我生成一個基於多文檔的程序,使用了NSArrayController類作為控製器,它的數據源為NSArray,其中每個元素由我定義的類Person來描述;主窗口中的tab_view作為主類中的outlets,主類為Document,它派生自NSDocument用來支持多文檔中的每一個文檔窗口。

添加add和remove按鈕,都與NSArrayController中的add和remove方法綁定;tab_view控件的兩列分別與Person類中的2個屬性綁定,每一行自然是Person數組中的每一個Person對象了。這樣每個視圖中的數據表示(tab_view)通過控製器與模式相連,視圖內容的改變(通過add和remove按鈕)也通過控製器從而導致模式數據的改變;而模式自身的改變(通過讀檔操作)也會更新視圖的顯示哦。這樣保證了視圖和模式的獨立性:模式可以在其他視圖上顯示,而視圖也可以綁定其他的模式。
最後,利用歸檔化實現了程序的save和open功能,也基本沒寫幾行代碼,而且save後的文件也自動與我們的程序綁定起來,如果雙擊該文件,會自動用我們的app打開哦,真是十分的方便。具體請看代碼:
//
// Document.h
// mac_doc
//
// Created by kinds on 14-7-7.
// Copyright (c) 2014年 kinds. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface Document : NSDocument{
IBOutlet NSTableView *tab_view;
NSMutableArray *persons;
}
-(void)setPersons:(NSMutableArray *)ary;
@end
//
// Document.m
// mac_doc
//
// Created by kinds on 14-7-7.
// Copyright (c) 2014年 kinds. All rights reserved.
//
#import "Document.h"
@interface Document ()
@end
@implementation Document
- (instancetype)init {
self = [super init];
if (self) {
// Add your subclass-specific initialization here.
persons = [[NSMutableArray alloc]init];
}
return self;
}
-(void)setPersons:(NSMutableArray *)ary{
if(ary == persons) return;
persons = ary;
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController {
[super windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController has loaded the document's window.
}
+ (BOOL)autosavesInPlace {
return YES;
}
- (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 @"Document";
}
- (NSData *)dataOfType:(NSString *)name error:(NSError **)out_err {
// Insert code here to write your document to data of the specified type. If outError != NULL, ensure that you create and set an appropriate error when returning nil.
// You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
[[tab_view window] endEditingFor:nil];
return [NSKeyedArchiver archivedDataWithRootObject:persons];
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)name \
error:(NSError **)out_err {
// Insert code here to read your document from the given data of the specified type. If outError != NULL, ensure that you create and set an appropriate error when returning NO.
// You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead.
// If you override either of these, you should also override -isEntireFileLoaded to return NO if the contents are lazily loaded.
NSMutableArray *new_ary = nil;
@try{
new_ary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}@catch(NSException *e){
NSLog(@"exception = %@",e);
if(out_err){
NSDictionary *d = [NSDictionary dictionaryWithObject:\
@"data is corrupted!" \
forKey:NSLocalizedFailureReasonErrorKey];
*out_err = [NSError errorWithDomain:NSOSStatusErrorDomain \
code:unimpErr userInfo:d];
}
return NO;
}
[self setPersons:new_ary];
return YES;
}
@end
//
// Person.h
// mac_doc
//
// Created by kinds on 14-7-7.
// Copyright (c) 2014年 kinds. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Person : NSObject <NSCoding>{
NSString *name;
float exp_raise;
}
@property(readwrite,copy)NSString *name;
@property(readwrite)float exp_raise;
@end
//
// Person.m
// mac_doc
//
// Created by kinds on 14-7-7.
// Copyright (c) 2014年 kinds. All rights reserved.
//
#import "Person.h"
@implementation Person
@synthesize name,exp_raise;
-(id)initWithCoder:(NSCoder *)coder{
self = [super init];
if(self){
name = [coder decodeObjectForKey:@"name"];
exp_raise = [coder decodeFloatForKey:@"exp_raise"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)coder{
[coder encodeObject:name forKey:@"name"];
[coder encodeFloat:exp_raise forKey:@"exp_raise"];
}
-(id)init{
self = [super init];
if(self){
exp_raise = 0.05;
name = @"no_name";
}
return self;
}
-(void)setNilValueForKey:(NSString *)key{
if([key isEqualToString:@"exp_raise"])
self.exp_raise = 0.0;
else
[super setNilValueForKey:key];
}
@end
程序執行界麵如下:

我們還可以設置私有存檔文件的圖標以及擴展名,如下圖:

最後更新:2017-04-03 05:38:58