【读书笔记】Objective-C编程之道:iOS设计设计模式解析(1)-原型模式
2013-09-12 00:21
423 查看
说在前面
在工作过程中,虽然有时会用到一些常见模式如工厂模式、单例模式、观察者模式等,但从来都没有系统地看过一本书,趁着现在时间比较充裕,学习一下《Objective-C编程之道:iOS设计设计模式解析》并在这里做些读书笔记,有些地方可能说得不尽人意,希望大家批评指出,互相学习。另外,有些图及语句会出自书本。原型模式的定义
原型模式(Prototype)即应用于“复制”操作的模式,此模式最初定义在《设计模式》(Addison-Wesley,1994),里面是这样定义的“使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象”。简单来理解就是根据这个原型创建新的对象,这种创建是指深复制,得到一份新的内存资源,而不是一个新的指针引用。浅复制与深复制
非指针型实例变量没有浅复制与深复制之分,像布尔型、整型、浮点型。浅复制与深复制是针对指针型实例变量说的,浅复制就只是复制了指针到副本中,原始对象与副本共享内存数据;深复制就是把内存的资源也复制了,原始对象和副本分别对应自己的内存数据。下面的示意图左边为浅复制,右边为深复制。Cocoa Touch框架为NSObject的派生类提供了复制协议即NSCopying协议,NSObject子类需要实现其方法(id)copyWithZone:(NSZone*)zone。NSObject有一个实例方法(id)copy,这个方法默认调用了[self copyWithZone:nil],当然在里面你可以实现浅层复制,也可以实现深层复制。
原型模式类图
Prototype类中包括一个Clone方法,Client知道Prototype,调用其复制方法clone即可得到多个实例,不需要手工去创建这些实例。ConcretePrototype为Prototype的子类,实现自身的clone方法,如果Client通过调用ConcretePrototype的clone方法,将返回ConcretePrototype的实例。例子
新建Prototype类,Prototype.h如下:#import <Foundation/Foundation.h> //Prototype使用了NSCopying协议,里面只有一个方法:- (id)copyWithZone:(NSZone *)zone; @interface Prototype : NSObject<NSCopying> //设置一个属性,用来检测复制的变化 @property(nonatomic, strong) NSString *name; @end
实现深复制,Prototype.m文件如下:
#import "Prototype.h" @implementation Prototype - (id)init { if (self = [super init]) { //初始化Prototype类时,将name设置如下 self.name = @"My name is Prototype"; } return self; } //实现NSCopying中的方法 - (id)copyWithZone:(NSZone *)zone { //调用allocWithZone方法,复制一个新对象 return [[[self class] allocWithZone:zone] init]; } @end
测试代码如下:
//创建Prototype实例 prototype Prototype *prototype = [[Prototype alloc] init]; //输出prototype NSLog(@"prototype:%@, name:%@", prototype, prototype.name); //通过prototype深复制出一个新的对象prototypeCopy Prototype *prototypeDeepCopy = [prototype copy]; //通过prototype直接赋值,其实就是复制了指针,属于浅复制,引用计数加1 Prototype *prototypeShallowCopy = prototype; NSLog(@"prototypeShallowCopy:%@, name:%@", prototypeShallowCopy, prototypeShallowCopy.name); //修改prototype prototype.name = @"My name is new Prototype"; //输出prototypeDeepCopy NSLog(@"prototype:%@, name:%@", prototype, prototype.name); NSLog(@"prototypeDeepCopy:%@, name:%@", prototypeDeepCopy, prototypeDeepCopy.name); NSLog(@"prototypeShallowCopy:%@, name:%@", prototypeShallowCopy, prototypeShallowCopy.name);
输出结果如下(省略时间及项目名):
prototype:<Prototype: 0x71330d0>, name:My name is Prototype prototypeShallowCopy:<Prototype: 0x71330d0>, name:My name is Prototype prototype:<Prototype: 0x71330d0>, name:My name is new Prototype prototypeDeepCopy:<Prototype: 0xc6138d0>, name:My name is Prototype prototypeShallowCopy:<Prototype: 0x71330d0>, name:My name is new Prototype
结论
1、我们在copyWithZone:(NSZone *)zone实现了深复制,通过prototype复制得到prototypeDeepCopy,从输出结果来看,内存地址与prototype是不一样的,另外复制得到prototypeCopy后修改了prototype的name,对prototypeCopy的name值没有影响,可判断为深复制;2、使用直接赋值得到的prototypeShallowCopy,内存地址与prototype一样,只是简单的指针复制,另外从修改了prototype的name值同时也影响了prototypeShallowCopy的name值也可以看出,这种为浅复制。
题外话
像NSString、NSDictionary这些类,本身已经实现了copyWithZone:(NSZone *)zone方法,直接使用如[NSString copy]调用即可。在复制后得到的副本,又可以分为可变副本(mutable copy)和不可变副本(immutablecopy)。通常在NSCopying协议规定的方法copyWithZone中返回不可变副本,在NSMutableCopying的mutableCopyWithZone方法中返回可变副本,然后调用copy和mutableCopy方法来得到副本。
NSDictionary类已经遵循NSCopying协议及NSMutableCopying协议,下面进行测试。
第一种情况:
NSDictionary *srcDic = [NSDictionary dictionaryWithObjectsAndKeys:@"value", @"key", nil]; NSDictionary *dicCopy = [srcDic copy];//注意这里用了copy NSLog(@"srcDic:%p, %@", srcDic, srcDic); NSLog(@"dicCopy:%p %@", dicCopy, dicCopy);
输出结果:
srcDic:0x8a73850, { key = value; } dicCopy:0x8a73850 { key = value; }
结论:
由[srcDic copy]得到的dicCopy,两者内存地址一致,由于copy返回的是不可变副本,系统只生成一份内存资源,此时的copy只是浅复制,retain作用一样。第二种情况:
NSDictionary *srcDic = [NSDictionary dictionaryWithObjectsAndKeys:@"value", @"key", nil]; NSDictionary *dicCopy = [srcDic mutableCopy];//注意这里使用了mutableCopy NSLog(@"srcDic:%p, %@", srcDic, srcDic); NSLog(@"dicCopy:%p %@", dicCopy, dicCopy);
输出结果:
srcDic:0x8938c50, { key = value; } dicCopy:0x8938b60 { key = value; }
结论:
由[srcDic mutableCopy]得到的dicCopy,两者内存地址不一致,由于mutableCopy返回的是可变副本,系统生成了新的内存资源,此时的mutableCopy是深复制。疑问:那么如果srcDic是NSMutableDictionary类型而使用copy,又会怎么样呢?且看第三种情况。第三种情况:
NSMutableDictionary *srcDic = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"value", @"key", nil]; NSMutableDictionary *dicCopy = [srcDic copy];//注意这里对NSMutableDictionary进行copy操作 NSLog(@"srcDic:%p, %@", srcDic, srcDic); NSLog(@"dicCopy:%p %@", dicCopy, dicCopy); [dicCopy setObject:@"newValue" forKey:@"key"];//尝试修改dicCopy里面的值
输出情况:
srcDic:0x7144ea0, { key = value; } dicCopy:0x71445c0 { key = value; } [__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x71445c0
结论:
由[srcDic mutableCopy]得到的dicCopy,两者内存地址不一致,即是copy对NSMutableDictionary类型进行了深复制,当尝试修改dicCopy里面的值时,发现报错了,修改不了,可以确定副本dicCopy是不可变副本。总的结论
对于系统中已经实现的同时支持NSCopying协议和NSMutableCopying协议的,copy总是返回不可变副本,mutableCopy总是返回可变副本。相关文章推荐
- Objective-C编程之道:iOS设计模式解析(一)工厂模式
- Objective-C 编程之道 iOS设计模式解析--第22章 代理
- Objective-C编程之道iOS设计模式单例解析(1)
- [置顶] Objective-C编程之道iOS设计模式单例解析(2)
- Objective-C编程之道iOS设计模式单例解析(2)
- Object-C编程之道 iOS设计模式解析--组合模式
- Object-C编程之道 iOS设计模式解析--迭代器模式
- Object-c 编程之道 IOS设计模式解析
- Object-C编程之道 iOS设计模式解析--工厂方法
- iOS书摘之Objective-C编程之道 iOS设计模式解析
- Object-C编程之道 iOS设计模式解析--中介者模式
- Objective-C编程之道iOS设计模式子类化单例疑惑
- Object-C编程之道 iOS设计模式解析--访问者模式
- Object-C编程之道 iOS设计模式解析--设计一个应用程序
- 【读书笔记】iOS设计模式解析(第二章)
- Object-C编程之道 iOS设计模式解析--单例模式
- iOS书摘之Objective-C编程之道 iOS设计模式解析
- iOS App开发中使用设计模式中的单例模式的实例解析
- Android 源码设计模式解析与实战 第2版 读书笔记1.6迪米特原则
- Objective-C KVO 编程 改善现有iOS代码设计