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以及归档化示例的更多相关文章
- obj-c编程15[Cocoa实例03]:MVC以及归档化演示样例
前面的博文里介绍了归档和解档,这里我们把它实际应用到一个简单的代码中去,将它作为一个多文档应用程序的打开和保存的背后支持.另外这里介绍一下MVC思想,这个在不论什么语言里都会有,它是一种设计思想,主要 ...
- [原创]obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用
原文链接:obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用 我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么 ...
- obj-c编程15[Cocoa实例01]:一个会发声的随机数生成器
哇!终于到了obj-c编程系列的第15篇喽,一路走过来满不容易的哦!(怎么个意思,这才哪到哪啊!),为了能够更好的练习obj-c在Cocoa框架上的编程,接下来会以N篇Cocoa实例的博文来巩固和记忆 ...
- obj-c编程15[Cocoa实例02]:KVC和KVO的实际运用
我们在第16和第17篇中分别介绍了obj-c的KVC与KVO特性,当时举的例子比较fun,太抽象,貌似和实际不沾边哦.那么下面我们就用一个实际中的例子来看看KVC与KVO是如何运用的吧. 该例中用到了 ...
- obj-c编程15[Cocoa实例04]:基于Core Data的多文档程序示例[未完待续]
上一个例子我们使用的模式数据实际上是基于一个Person数组,现在我们看一下如何使用Cocoa中的Core Data框架支持,几乎不用写一行代码,完成模式数据的建立. 我们这里模式的元素使用的是Car ...
- 编程体系结构(08):Spring.Mvc.Boot框架
本文源码:GitHub·点这里 || GitEE·点这里 一.Spring框架 1.框架概述 Spring是一个开源框架,框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 ...
- C#网络编程TCP通信实例程序简单设计
C#网络编程TCP通信实例程序简单设计 采用自带 TcpClient和TcpListener设计一个Tcp通信的例子 只实现了TCP通信 通信程序截图: 压力测试服务端截图: 俩个客户端链接服务端测试 ...
- 零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I
原文:零元学Expression Blend 4 - Chapter 15 用实例了解互动控制项「Button」I 本章将教大家如何更改Button的预设Template,以及如何在Button内设置 ...
- ASP.NET MVC 4 插件化架构简单实现-实例篇
先回顾一下上篇决定的做法: 1.定义程序集搜索目录(临时目录). 2.将要使用的各种程序集(插件)复制到该目录. 3.加载临时目录中的程序集. 4.定义模板引擎的搜索路径. 5.在模板引擎的查找页面方 ...
随机推荐
- Struts2处理流程性需求的一种解决方案
在应用程序设计中,经常出现如下的需求. 查看用户填写的数据,而且数据是分页填写. 看下面这个情况 用户的信息有三页,分别是Form abc. 现在的问题是,后面的逻辑该如何设计. 如果把,FormAB ...
- 剑指Offer——二分查找算法
剑指Offer--二分查找算法 前言 本片博文主要讲解查找算法的相关知识.重点介绍二分查找. 二分查找算法是在有序数组中用到的较为频繁的一种查找算法,在未接触二分查找算法时,最通用的一种做法是,对数组 ...
- Hibernate配置文件current_session_context_class的意思
转自:http://shuaigg-babysky.iteye.com/blog/563423 此设置的作用如下: What does sessionFactory.getCurrentSession ...
- 2、Android构建本地单元测试
如果你的单元测试在Android中没有依赖或者只有简单的以来,你可以在你的本地开发环境中运行你的测试.这种测试比较高效因为它能让你避免将整个app安装到物理设备或虚拟机中执行单元测试.最后,执行单元测 ...
- Android开发学习之路--UI之简单聊天界面
学了很多的ui的知识,这里就来实现个聊天的界面,首先来实现个layout的xml,代码如下: <?xml version="1.0" encoding="utf-8 ...
- Cocos2D中Node的userObject实例变量使用时一个要注意的地方
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中,CCNode对象有一个ivar为us ...
- (七十九)MapKit的基本使用
MapKit是苹果公司开发的用于显示地图和实现定位.导航的地图框架. MapKit View可以通过storyboard.xib创建,也可以通过代码直接创建. 需要注意的是,通过storyboard和 ...
- UNIX网络编程——TCP连接的建立和断开、滑动窗口
一.TCP段格式: TCP的段格式如下图所示: 源端口号与目的端口号:源端口号和目的端口号,加上IP首部的源IP地址和目的IP地址唯一确定一个TCP连接. 序号:序号表示在这个报文段中的第一个数据字节 ...
- HDFS追本溯源:体系架构详解
Hadoop是一个开发和运行处理大规模数据的软件平台,是Apache的一个用Java语言实现开源软件框架,实现在大量计算机组成的集群中对海量数据进行分布式计算.用户可以在不了解分布式底层细节的情况下, ...
- CentOS下Mariadb表名大小写的问题
今天在linux上跑一个系统 发现数据库报错,说找不到表 问题是,我已经建立了表呀. 我把报错的那个表 复制到命令行 运行一下. 发现是大小写的问题. 那问题就简单了. 网上百度可以知道 打开/etc ...