好吧,上一篇我怎么也没想到会写那么多字那么少的代码,希望这一篇不会如此哦。

言归正传,对象的复制分为浅复制和深复制,前者只是复制对象的引用,当原对象的内容发生变化时,复制对象的内容也会发生变化,毕竟他们都指向同一个对象啊!有人可能会说了,原对象如果是不可改变对象,不就可以放心的做浅复制了吗?因为不能修改它的值,也就不用担心复制对象的内容改变啦!还是不行哦!我们设想如下情况:

#import <Foundation/Foundation.h>

#define msg(...) NSLog(__VA_ARGS__)

int main(int argc,char *argv[])
{
	@autoreleasepool{
		//NSMutableString *val = @"val0",*key = @"key0";
		NSMutableString *val = [NSMutableString stringWithString:@"val0"],\
			*key = [NSMutableString stringWithString:@"key0"];
		NSDictionary *dict_old,*dict_new;
		dict_old = [[NSDictionary alloc] initWithObjectsAndKeys:val,key,@"val1",@"key1",\
			@"val2",@"key2",nil];	//不要忘记最后的nil哦!
		msg(@"%@",dict_old);

		void (^block)(id key,id obj,BOOL *stop) = ^(id key,id obj,BOOL *stop){
			msg(@"key[%@]:val[%@]",key,obj);
			*stop = NO;
		};
		[dict_old enumerateKeysAndObjectsUsingBlock:block];

		dict_new = [dict_old copy];	//浅copy
		[val insertString:@"_fixed" atIndex:[val length]];
		[key insertString:@"_fixed" atIndex:[key length]];
		//[val setString:@"fix_val"];
		//[key setString:@"fix_key"];

		//注意,2个dict的val0值都变了,但key0值都没变,说明字典对key是深拷贝的。
		//另外可以看出即使是不可变对象dict_old也不能保证其元素一定是不可改变的,
		//如果不是,则仍然会发生浅拷贝后被改变的情况。
		msg(@"%@\n**************************%@",dict_old,dict_new);

	}
	return 0;
}

运行结果如下:

apple@kissAir: objc_src$clang -fobjc-arc -framework Foundation 5.m -o 5

apple@kissAir: objc_src$./5

2014-07-03 11:47:52.496 5[1447:507] {

key0 = val0;

key1 = val1;

key2 = val2;

}

2014-07-03 11:47:52.498 5[1447:507] key[key1]:val[val1]

2014-07-03 11:47:52.498 5[1447:507] key[key0]:val[val0]

2014-07-03 11:47:52.499 5[1447:507] key[key2]:val[val2]

2014-07-03 11:47:52.499 5[1447:507] {

key0 = "val0_fixed";

key1 = val1;

key2 = val2;

}

**************************{

key0 = "val0_fixed";

key1 = val1;

key2 = val2;

}


再看另外一种情况:

#import <Foundation/Foundation.h>

#define msg(...) NSLog(__VA_ARGS__)
#define mstr(x) [NSMutableString stringWithString:x]

int main(int argc,char *argv[])
{
	@autoreleasepool{
		NSMutableArray *m_ary = [NSMutableArray arrayWithObjects:\
			mstr(@"one"),mstr(@"two"),mstr(@"three"),nil];
		NSMutableArray *m_ary_new;
		NSMutableString *mstr;

		for(NSString *str in m_ary)
			msg(@"   %@",str);

		m_ary_new = [m_ary mutableCopy];
		mstr = [m_ary objectAtIndex:0];
		[mstr appendString:@"_fixed"];

		msg(@"%@\n****************************%@",m_ary,m_ary_new);
	}
	return 0;
}

你能猜到运行结果吗?

apple@kissAir: objc_src$./5

2014-07-03 12:00:01.235 5[1494:507]    one

2014-07-03 12:00:01.237 5[1494:507]    two

2014-07-03 12:00:01.237 5[1494:507]    three

apple@kissAir: objc_src$clang -fobjc-arc -framework Foundation 5.m -o 5

apple@kissAir: objc_src$./5

2014-07-03 12:02:17.727 5[1504:507]    one

2014-07-03 12:02:17.729 5[1504:507]    two

2014-07-03 12:02:17.730 5[1504:507]    three

2014-07-03 12:02:17.731 5[1504:507] (

"one_fixed",

two,

three

)

****************************(

"one_fixed",

two,

three

)

为什么我改变m_ary的元素,m_ary_new同位置的元素值也会变化呢?其实对于浅拷贝来说m_ary每个元素只是拷贝其引用到新的m_ary_new的元素上,所以...没有所以了 :),那如果我要改变m_ary的元素同时m_ary_new不发生变化该怎么办呢?你可以创建一个新的元素喽:

mstr = [NSMutableString stringWithString:[m_ary objectAtIndex:0]];

[mstr appendString:@"fixed"];
[m_ary replaceObjectAtIndex:0 withObject:mstr];

但是对于单一的可变字符串对象,copy拷贝的是深拷贝,这个要注意下:

#import <Foundation/Foundation.h>

#define msg(...) NSLog(__VA_ARGS__)
#define mstr(x) [NSMutableString stringWithString:x]

int main(int argc,char *argv[])
{
	@autoreleasepool{
		NSMutableString *mstr0 = mstr(@"test_str"),*mstr1;
		mstr1 = [mstr0 copy];
		[mstr0 appendFormat:@"_%d_%d",101,102];
		msg(@"%@ and %@",mstr0,mstr1);
	}
	return 0;
}

运行结果如下:

apple@kissAir: objc_src$./5

2014-07-03 13:34:28.805 5[1762:507] test_str_101_102 and test_str

F库类实现了名为copy和mutableCopy的方法,可以使用他们来创建对象的副本。通过实现一个符合<NSCopying>协议的方法来完成此任务。如果类要区分产生可变副本和不可变副本,还要根据<NSMutableCopying>协议实现一个方法啊。

我们想象一个例子:数组A的一个可变副本copy到数组B,无论数组A是否可变,如果将B中第一个元素删除,A会不会受影响?答案是:不会!因为浅拷贝拷贝了数组中的每个元素的空间,即每个元素本身是深拷贝,只是指向的对象是一样的(浅拷贝),所以各个数组的元素是不受影响的(除非它们指向的对象值发生了变化,就像前2个代码示例一样。)

对于我们自己的类,只有实现<NSCopying>协议才可以调用copy方法(废话嘛)。在实现该协议时,类必须实现copyWithZone方法来响应copy消息。如果还要区分不可变副本,还要根据<NSMutableCopying>协议实现mutableCopyWithZone方法哦。如果2个方法都实现这前者返回不可变对象后者返回可变对象。

@implementation Some_class <NSCopying>
	-(id)copyWithZone:(NSZone*)zone{
		Some_class *new_obj = [[Some_class allocWithZone:zone] init];
		//如果该类可能会被继承则上一句改为:
		//id new_obj = [[[self class] allocWithZone:zone] init];
		[new_obj set_x:x set_y:y];
		return new_obj;
	}
@end

zone参数与不同的存储区有关,你可以在程序中分配并使用这些存储区。直接传递给allocWithZone即可。

如果编写了类的copyWithZone方法,而该类的超类也实现了<NSCopying>协议,则应该先调用超类的copy方法一复制继承来的实例变量,然后加入自己代码赋值新的实例变量(如果有的话)。你必须确定是否在类中实现浅拷贝或深拷贝,并编写文档,以告知类的其他使用者。

obj-c编程12:复制对象的更多相关文章

  1. Effective C++ -----条款12: 复制对象时勿忘其每一个成分

    Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个cop ...

  2. EC读书笔记系列之7:条款12 复制对象时勿忘其每一个成分

    记住: ★copying函数应确保复制“对象内的所有成员变量”及“所有base class成分” ★不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两 ...

  3. Effective C++(12) 复制对象时要复制每一个成员

    问题聚焦: 负责拷贝的两个操作:拷贝构造函数和重载赋值操作符. 一句话总结,确保被拷贝对象的所有成员变量都做一份拷贝. Demo   void logCall(const std::string&am ...

  4. Effective C++ .12 复制对象-拷贝构造函数的编写

    当我们自己编写拷贝构造函数时,编译器就不会为该类生成默认拷贝构造函数了,对于assignment operator也是如此. 1. 拷贝构造函数中记得调用父类的拷贝构造函数,或者相应复制过程 clas ...

  5. EC笔记:第二部分:12、复制对象时勿忘其每一个成分

    EC笔记:第二部分:12.复制对象时勿忘其每一个成分 1.场景 某些时候,我们不想使用编译器提供的默认拷贝函数(包括拷贝构造函数和赋值运算符),考虑以下类定义: 代码1: class Point{ p ...

  6. Effective C++ 条款12:复制对象时勿忘其每一个成分

    void logCall(const std::string& funcName); class Customer { public: ... Customer (const Customer ...

  7. Effective C++ 条款11,12 在operator= 中处理“自我赋值” || 复制对象时不要忘记每一个成分

    1.潜在的自我赋值     a[i] = a[j];     *px = *py; 当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名. 现在担心的问题是:假如指向同一个对象, ...

  8. 条款12:复制对象时勿忘其每一个成分(Copy all parts of an object)

    NOTE: 1.Copying 函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 2.不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个 ...

  9. 13_Python的面向对象编程-类class,对象object,实例instance

    1.面向对象概述 1.类是用来描述对象的工具,把拥有相同属性和行为的对象分为一组     2.对象是由类实例化出来的一个具体的对象         属性: 对象拥有的名词,用变量表示         ...

随机推荐

  1. android view事件分发机制

    首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...

  2. 12 PopupWindow

    PopupWindow创建方式 PopupWindow pop = new PopupWindow() PopupWindow pop = new PopupWindow(上下文, 填充宽, 填充高) ...

  3. Android简易实战教程--第十三话《短信备份和还原~三》

    之前写过短信备份的小案例,哪里仅仅是虚拟了几条短信信息.本篇封装一个业务类,且直接通过内容提供者,访问本系统的短信信息,再提供对外接口.如果想要短信备份和短信还原,直接复制这段代码即可.对于您调用这个 ...

  4. [django]项目打包构建

    django项目的结构大体上都是类似,打包主要的功能就是把一些不需要部署的文件剔除,把需要部署的文件直接压缩打包. 这里还想集成一个配置文件模板生成配置文件的过程,或者写一个配置文件生成的工具,不用每 ...

  5. Hadoop-1.0.4伪分布安装与配置

    1.采用伪分布模式安装      将hadoop-****.tar.gz复制到linux的/usr/local目录下. 2.解压,重命名      #tar -xzvf hadoop-1.0.4.ta ...

  6. 01_Weblogic课程之概念篇:代理服务器,web服务器,应用程序服务器,JNDI概念,JTA概念,Java消息服务,Java验证和授权(JAAS),Java管理扩展,Web客户机,客户机应用程序

     1 什么是服务器 Weblogic中服务器分为两种,一种是受管服务器,另外一种是管理服务器. Weblogic课程(Weblogic是Oracle公司的,最开始的是BEA公司的) 一 系统管理 ...

  7. 基于IMX515EVK+WINCE6.0---支持PB6.0通过USB下载镜像文件

    基于IMX515EVK+WINCE6.0---支持PB6.0通过USB下载镜像文件 在INAND还没有写入镜像文件之前,通过ATK工具烧录xldr.nb0和eboot.nbo到INAND中,见相关链接 ...

  8. Linux下修改Oracle数据库字符集命令

    常见情形:从服务器备份Oracle数据库后再到本地机器上还原Oracle数据库的时候经常会碰见数据库字符编码不一致的情况,可以用以下命令来修改本地的Oracle数据库字符编码,然后顺利还原Oracle ...

  9. JSON 的数据转换格式(DataTable或DataSet) -善良公社项目

    这两天在使用JqueryEasyUI框架绑定数据并实现自动分页时,由于框架的限制需要使用Json数据的来传递与获取数据: JSON的全称是JavaScript Object Notation, 是一种 ...

  10. 72【leetcode】经典算法- Lowest Common Ancestor of a Binary Search Tree(lct of bst)

    题目描述: 一个二叉搜索树,给定两个节点a,b,求最小的公共祖先 _______6______ / \ ___2__ ___8__ / \ / \ 0 _4 7 9 / \ 3 5 例如: 2,8 - ...