前面的博文里介绍了归档和解档,这里我们把它实际应用到一个简单的代码中去,将它作为一个多文档应用程序的打开和保存的背后支持。另外这里介绍一下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以及归档化示例的更多相关文章

  1. obj-c编程15[Cocoa实例03]:MVC以及归档化演示样例

    前面的博文里介绍了归档和解档,这里我们把它实际应用到一个简单的代码中去,将它作为一个多文档应用程序的打开和保存的背后支持.另外这里介绍一下MVC思想,这个在不论什么语言里都会有,它是一种设计思想,主要 ...

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

    原文链接:obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用 我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么 ...

  3. obj-c编程15[Cocoa实例01]:一个会发声的随机数生成器

    哇!终于到了obj-c编程系列的第15篇喽,一路走过来满不容易的哦!(怎么个意思,这才哪到哪啊!),为了能够更好的练习obj-c在Cocoa框架上的编程,接下来会以N篇Cocoa实例的博文来巩固和记忆 ...

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

    我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么下面我们就用一个实际中的例子来看看KVC与KVO是如何运用的吧. 该例中用到了 ...

  5. obj-c编程15[Cocoa实例04]:基于Core Data的多文档程序示例[未完待续]

    上一个例子我们使用的模式数据实际上是基于一个Person数组,现在我们看一下如何使用Cocoa中的Core Data框架支持,几乎不用写一行代码,完成模式数据的建立. 我们这里模式的元素使用的是Car ...

  6. 编程体系结构(08):Spring.Mvc.Boot框架

    本文源码:GitHub·点这里 || GitEE·点这里 一.Spring框架 1.框架概述 Spring是一个开源框架,框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 ...

  7. C#网络编程TCP通信实例程序简单设计

    C#网络编程TCP通信实例程序简单设计 采用自带 TcpClient和TcpListener设计一个Tcp通信的例子 只实现了TCP通信 通信程序截图: 压力测试服务端截图: 俩个客户端链接服务端测试 ...

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

    原文:零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I 本章将教大家如何更改Button的预设Template,以及如何在Button内设置 ...

  9. ASP.NET MVC 4 插件化架构简单实现-实例篇

    先回顾一下上篇决定的做法: 1.定义程序集搜索目录(临时目录). 2.将要使用的各种程序集(插件)复制到该目录. 3.加载临时目录中的程序集. 4.定义模板引擎的搜索路径. 5.在模板引擎的查找页面方 ...

随机推荐

  1. GraphX PageRank

    GraphX算法模型:PageRank 一:算法介绍         PageRank是Google专有的算法,用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度. 一个页面的"得 ...

  2. UNIX网络编程——Socket通信原理和实践

    我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠so ...

  3. Java在Linux下 不能处理图形的解决办法 Can't connect to X11 window server

    java在图形处理时调用了本地的图形处理库.在利用Java作图形处理(比如:图片缩放,图片签名,生成报表)时,如果运行在windows上不会出问题.如果将程序移植到Linux/Unix上的时候有可能出 ...

  4. UNIX网络编程——套接字选项(心跳检测、绑定地址复用)

    /* 设置套接字选项周期性消息检测连通性 心跳包. 心博.主要用于长连接. * 参数:套接字, 1或0开启, 首次间隔时间, 两次间隔时间, 断开次数 */ void setKeepAlive( in ...

  5. volatile实现可见性但不保证原子性

    volatile实现可见性但不保证原子性 volatile关键字: 能够保证volatile变量的可见性 不能保证volatile变量复合操作的原子性 volatile如何实现内存可见性: 深入来说: ...

  6. HTTP请求方法

    HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, ...

  7. Android官方命令深入分析之Hierarchy Viewer

    Hierarchy Viewer允许你调试和优化用户界面.它提供了一个层可视的方式来显示. 启动Hierarchy Viewer,如下: 在Android Studio中,选择Tools > A ...

  8. java实现:将一个数各个位数相加

    前面已经实现过这个程序,现在我们就不多说了,直接更改C的源码,实现这个JAVA程序. import java.util.Scanner; public class HelloWorld { publi ...

  9. 【一天一道LeetCode】#130. Surrounded Regions

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  10. 关于CKEditor4.5.6的使用,自定义toolbar配置,上传图片案例(SpringMVC+MyBatis案例),自定义行高,去编辑器的中内容,将编辑器中内容设置到指定的位置等

     关于CKEditor的一个配置整理,改文件为config.js: 文件内容如下: /** * @license Copyright (c) 2003-2016, CKSource - Frede ...