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

程序执行界面如下:

我们还可以设置私有存档文件的图标以及扩展名,如下图:

obj-c编程15[Cocoa实例03]:MVC以及归档化示例,布布扣,bubuko.com

时间: 2024-12-29 15:06:30

obj-c编程15[Cocoa实例03]:MVC以及归档化示例的相关文章

[原创]obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用

原文链接:obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用 我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么下面我们就用一个实际中的例子来看看KVC与KVO是如何运用的吧. 该例中用到了3种新的控件类型:NSTableView.NSSlider以及简单的NSTextField类型.按说不能再在Random类里添加不沾边的新增功能了,但是为了简单,我还是把所有东西都放在Random类里喽.程序运行时界面如下

obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用

我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么下面我们就用一个实际中的例子来看看KVC与KVO是如何运用的吧. 该例中用到了3种新的控件类型:NSTableView.NSSlider以及简单的NSTextField类型.按说不能再在Random类里添加不沾边的新增功能了,但是为了简单,我还是把所有东西都放在Random类里喽.程序运行时界面如下: 大家可以看到左上角的文本域控件用来显示当前音量,因为它和Random类里的

并发编程 15—— 线程池 之 原理二

Java并发编程实践 目录 并发编程 01—— ConcurrentHashMap 并发编程 02—— 阻塞队列和生产者-消费者模式 并发编程 03—— 闭锁CountDownLatch 与 栅栏CyclicBarrier 并发编程 04—— Callable和Future 并发编程 05—— CompletionService : Executor 和 BlockingQueue 并发编程 06—— 任务取消 并发编程 07—— 任务取消 之 中断 并发编程 08—— 任务取消 之 停止基于线

零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I

原文:零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I 本章将教大家如何更改Button的预设Template,以及如何在Button内设置动画. ? 本章将教大家如何更改Button的预设Template,以及如何在Button内设置动画. ? ? ? 01 开启一个新专案,并且置入一个Button,调整到适当大小 ? 在Properties->可以调整Button的外观,基本设定都跟先前的教学雷同 不熟的人请看如何用Blend制作一

1036. 跟奥巴马一起编程(15)

1036. 跟奥巴马一起编程(15) 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝"计算机科学教育周"正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形.现在你也跟他一起画吧! 输入格式: 输入在一行中给出正方形边长N(3<=N<=20)和组成正方形边的某种字符C,间隔一个空格. 输出格式: 输出由给定字符C画出的正方形.但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们

PAT-乙级-1036. 跟奥巴马一起编程(15)

1036. 跟奥巴马一起编程(15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形.现在你也跟他一起画吧! 输入格式: 输入在一行中给出正方形边长N(3<=N<=20)和组成正方形边的某种字符C,间隔一个

Java Swing界面编程(15)---JScrollPane

在一般的图形界面中,如果显示的区域不够大,往往会出现滚动条以方便用户的浏览,在Swing中JScrollPane的主要的功能就是为了显示的内容加入水平滚动条. package com.beyole.util; import java.awt.Container; import java.io.File; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.sw

Programming Ability Test学习 1036. 跟奥巴马一起编程(15)

1036. 跟奥巴马一起编程(15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形.现在你也跟他一起画吧! 输入格式: 输入在一行中给出正方形边长N(3<=N<=20)和组成正方形边的某种字符C,间隔一个

Knockout官网实例在MVC下的实现-01,实现Hello world

本篇使用Knockout在MVC下实现"Hello World",对应的官网实例在这里. View视图 Knockout的一个特点是:声明式绑定,即Declarative bindings.暂且不管业务逻辑,先把关注点放在界面UI上,即"MVVM"模式中的第二个"V", 也就是View视图.根据Knockout的语法,创建如下界面: <div> <p>First name:<input data-bind="