在开发过程中我们经常会遇到对象拷贝的问题,下面我们分别讨论赋值操作、对象拷贝、以及浅拷贝(Shallow copy)与深拷贝(Deep copy)的区别与各自的实现方式。

一、不同对象的赋值操作

Objective-C中有两类对象,一类是结构体(或者基本数据类型也算),另一类是NSObject对象。

对于结构体,代码直接会操作其实体,因此赋值操作会创建一个源对象的副本(一个新的对象);而对于NSObject对象,必
须使用指针来操作对象,所以其赋值操作相当于复制了指针,而非对象,也就是说赋值操作使得源指针和新指针都指向同一个NSObject对象。这样讲有些难
以理解,请看下面的代码:

  1. // main.m
  2. #import <Foundation/Foundation.h>
  3. @interface TestObject : NSObject
  4. {
  5. @public
  6. int x;
  7. int y;
  8. }
  9. @end
  10. @implementation TestObject
  11. @end
  12. typedef struct TestStruct
  13. {
  14. int x;
  15. int y;
  16. }
  17. TestStruct;
  18. int main(int argc, const char * argv[])
  19. {
  20. @autoreleasepool {
  21. TestStruct ts1 = {100, 50};
  22. NSLog(@"ts1: %p, %d, %d", &ts1, ts1.x, ts1.y);
  23. TestStruct ts2 = ts1;
  24. NSLog(@"ts2: %p, %d, %d", &ts2, ts2.x, ts2.y);
  25. TestObject* to1 = [[[TestObject alloc] init] autorelease];
  26. NSLog(@"to1: %p, %d, %d", to1, to1->x, to1->y);
  27. TestObject* to2 = to1;
  28. NSLog(@"to2: %p, %d, %d", to2, to2->x, to2->y);
  29. }
  30. return 0;
  31. }

程序的运行结果如下:

  1. ts1: 0x7fff63463898, 100, 50
  2. ts2: 0x7fff63463890, 100, 50
  3. to1: 0x7fc342d00370, 0, 0
  4. to2: 0x7fc342d00370, 0, 0


序代码首先定义了一个类TestObject(继承自NSObject),然后又定义了一个结构体TestStruct。这两者都包含两个整型的成员变量
x和y。然后在main函数中,程序首先为TestStruct结构体ts1分配内存空间,并为其成员变量赋初值,x为100,y为50。然后通过
NSLog函数打印出该结构体的地址和成员变量的值,即输出的第一行内容。接着,程序执行了赋值语句,将ts1赋值给另一个TestStruct结构体对
象ts2,这条语句会为ts2分配另一块内存,然后把ts1的每个成员变量的值复制过来。第二行输出也可以看出来,地址不一样了,所以如果修改ts1的成
员变量的值,是不会影响ts2的。

接着再来看TestObject。程序接着使用alloc静态方法分配了一块新的内存空间,然后通过init实例方法进行初
始化(所有成员变量的值为0),最后将该内存空间的首地址返回。to1的实质就是一个指针,指向创建的TestObject对象。接着,程序将to1赋值
给to2。to2也是一个指向TestObject对象的指针,其值与to1一样,即两者都指向同一个对象。所以在这种情况下,对to1的修改会同时影响
to2。

二、对象拷贝

Foundation框架的NSObject类提供了两个方法,分别是copy和mutableCopy方法,用于对
NSObject对象进行拷贝操作。copy方法会调用NSCopying协议的copyWithZone:方法,而mutableCopy会调
用 NSMutableCopying协议的mutableCopyWithZone:方法。将上面的代码修改如下:

  1. #import <Foundation/Foundation.h>
  2. @interface TestObject : NSObject
  3. {
  4. @public
  5. int x;
  6. int y;
  7. }
  8. @end
  9. @implementation TestObject
  10. - (NSString*)description
  11. {
  12. return [NSString stringWithFormat:@"%@: %p, x: %d, y: %d", [self class], self, x, y];
  13. }
  14. @end
  15. typedef struct TestStruct
  16. {
  17. int x;
  18. int y;
  19. }
  20. TestStruct;
  21. int main(int argc, const char * argv[])
  22. {
  23. @autoreleasepool
  24. {
  25. TestObject* to1 = [[[TestObject alloc] init] autorelease];
  26. to1->x = 100; to1->y = 50;
  27. TestObject* to2 = [[[TestObject alloc] init] autorelease];
  28. to2->x = 200; to2->y = 400;
  29. TestObject* to3 = [[[TestObject alloc] init] autorelease];
  30. to3->x = 300; to3->y = 500;
  31. //创建包含to1, to2, to3的数组array1
  32. NSArray* array1 = [NSArray arrayWithObjects:to1, to2, to3, nil];
  33. NSLog(@"array1: %p, \n%@", array1, array1);
  34. //array2是array1调用copy的结果
  35. NSArray* array2 = [array1 copy];
  36. NSLog(@"array2: %p, \n%@", array2, array2);
  37. [array2 release];
  38. //mutableArray2是array1调用mutableCopy的结果
  39. NSMutableArray* mutableArray2 = [array1 mutableCopy];
  40. NSLog(@"mutableArray2: %@, %p, \n%@", [mutableArray2 class], mutableArray2, mutableArray2);
  41. [mutableArray2 removeLastObject];
  42. NSLog(@"After remove last object of mutableArray2");
  43. NSLog(@"array1: %p, \n%@", array1, array1);
  44. NSLog(@"array2: %p, \n%@", array2, array2);
  45. NSLog(@"mutableArray2: %p, \n%@", mutableArray2, mutableArray2);
  46. //mutableArray3是mutableArray2调用mutableCopy的结果
  47. NSMutableArray* mutableArray3 = [mutableArray2 mutableCopy];
  48. NSLog(@"mutableArray3: %p, \n%@", mutableArray3, mutableArray3);
  49. [mutableArray2 release];
  50. //array4是mutableArray3调用copy的结果
  51. NSArray* array4 = [mutableArray3 copy];
  52. NSLog(@"array4: %@, %p, \n%@", [array4 class], array4, array4);
  53. [mutableArray3 release];
  54. [array4 release];
  55. }
  56. return 0;
  57. }

程序的运行结果如下:

  1. 2012-03-22 19:20:49.548 ObjectCopy[18042:403] array1: 0x7f9071414820,
  2. (
  3. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  4. "TestObject: 0x7f90714141c0, x: 200, y: 400",
  5. "TestObject: 0x7f9071414230, x: 300, y: 500"
  6. )
  7. 2012-03-22 19:20:49.550 ObjectCopy[18042:403] array2: 0x7f9071414820,
  8. (
  9. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  10. "TestObject: 0x7f90714141c0, x: 200, y: 400",
  11. "TestObject: 0x7f9071414230, x: 300, y: 500"
  12. )
  13. 2012-03-22 19:20:49.551 ObjectCopy[18042:403] mutableArray2: __NSArrayM, 0x7f9072800000,
  14. (
  15. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  16. "TestObject: 0x7f90714141c0, x: 200, y: 400",
  17. "TestObject: 0x7f9071414230, x: 300, y: 500"
  18. )
  19. 2012-03-22 19:20:49.552 ObjectCopy[18042:403] After remove last object of mutableArray2
  20. 2012-03-22 19:20:49.552 ObjectCopy[18042:403] array1: 0x7f9071414820,
  21. (
  22. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  23. "TestObject: 0x7f90714141c0, x: 200, y: 400",
  24. "TestObject: 0x7f9071414230, x: 300, y: 500"
  25. )
  26. 2012-03-22 19:20:49.553 ObjectCopy[18042:403] array2: 0x7f9071414820,
  27. (
  28. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  29. "TestObject: 0x7f90714141c0, x: 200, y: 400",
  30. "TestObject: 0x7f9071414230, x: 300, y: 500"
  31. )
  32. 2012-03-22 19:20:49.553 ObjectCopy[18042:403] mutableArray2: 0x7f9072800000,
  33. (
  34. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  35. "TestObject: 0x7f90714141c0, x: 200, y: 400"
  36. )
  37. 2012-03-22 19:20:49.557 ObjectCopy[18042:403] mutableArray3: 0x7f90729000d0,
  38. (
  39. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  40. "TestObject: 0x7f90714141c0, x: 200, y: 400"
  41. )
  42. 2012-03-22 19:20:49.558 ObjectCopy[18042:403] array4: __NSArrayI, 0x7f9071416e70,
  43. (
  44. "TestObject: 0x7f90714141b0, x: 100, y: 50",
  45. "TestObject: 0x7f90714141c0, x: 200, y: 400"
  46. )

程序的运行结果有几点值得注意,首先是array1与array2的地址相同,因为NSArray对象在创建之后是不可以修
改的。其次,NSArray的mutableCopy方法会返回一个NSMutableArray对象。第三,对于NSArray或者
NSMutableArray来说,mutableCopy方法会创建新的可变数组对象,但其每个数组成员的值仅仅是原数组的一个指针赋值,这就是浅拷
贝。而与之相对的则是深拷贝,即复制数组时不是复制数组每个元素的引用,而是创建一个与之相同的新对象。第四,在NSArray对象上调用
mutableCopy方法返回一个NSMutableArray对象,而在NSMutableArray对象上调用copy方法则返回一个
NSArray对象,而不是NSMutableArray对象。

当然,以上讨论的是Foundation框架中的NSArray与NSMutableArray类,如果想要实现对自己创建的类的对象进行拷贝,则需要让类实现NSCopying协议。

ObjectiveC中的赋值,对象拷贝,浅拷贝与深拷贝的更多相关文章

  1. python中的赋值与拷贝(浅拷贝与深拷贝)

    1.赋值与拷贝 直接赋值(b=a)是传引用,b改动a也会改动. a = [1, 2, 3, 4] b = a b[1] = 999 print(a, b) #[1, 999, 3, 4] [1, 99 ...

  2. Python中的赋值(复制)、浅拷贝、深拷贝之间的区别

    1.赋值: 只是复制了新对象的引用,不会开辟新的内存空间.  2.浅拷贝: 创建新对象,其内容是原对象的引用.    浅拷贝有三种形式:切片操作,工厂函数,copy模块中的copy函数.    如: ...

  3. Python3中的赋值操作、浅拷贝与深拷贝

    一:关于赋值操作与浅拷贝 1.变量的赋值 首先以一个例子来说明一下:定义变量a = 1,使b = a.开始的情况下打印a与b都为1(显而易见,哈哈) 但是接下来,我们做一下改动,令 a = 222,再 ...

  4. Java对象的浅拷贝和深拷贝&&String类型的赋值

    Java中的数据类型分为基本数据类型和引用数据类型.对于这两种数据类型,在进行赋值操作.方法传参或返回值时,会有值传递和引用(地址)传递的差别. 浅拷贝(Shallow Copy): ①对于数据类型是 ...

  5. Python中的赋值和拷贝

    赋值 在python中,赋值就是建立一个对象的引用,而不是将对象存储为另一个副本.比如: >>> a=[1,2,3] >>> b=a >>> c= ...

  6. Python中的可变对象与不可变对象、浅拷贝与深拷贝

    Python中的对象分为可变与不可变,有必要了解一下,这会影响到python对象的赋值与拷贝.而拷贝也有深浅之别. 不可变对象 简单说就是某个对象存放在内存中,这块内存中的值是不能改变的,变量指向这块 ...

  7. JS数组和对象的浅拷贝和深拷贝

    共勉~ 在许多编程语言中,传递参数和赋值是通过值的直接复制或者引用复制完成的.在JavaScript中,对于值是直接进行复制还是引用复制在语法上是没有区别的,完全是根据值的类型来决定的. 在JavaS ...

  8. js对象的浅拷贝与深拷贝

    浅拷贝和深拷贝都是对于JS中的引用类型而言的,浅拷贝就只是复制对象的引用(堆和栈的关系,原始(基本)类型Undefined,Null,Boolean,Number和String是存入堆,直接引用,ob ...

  9. Java中的clone方法-理解浅拷贝和深拷贝

    最近学到Java虚拟机的相关知识,更加能理解clone方法的机制了 java中的我们常常需要复制的类型有三种: 1:8种基本类型,如int,long,float等: 2:复合数据类型(数组): 3:对 ...

随机推荐

  1. 3、css边框以及其他常用样式

    一.边框 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  2. python 之 exec命令

    参数1:字符串形式的命令 参数2:全局作用域(字典形式),如果不指定默认使用globals() 参数3:局部作用域(字典形式),如果不指定默认使用locals() g= { 'x':1, 'y':2 ...

  3. Flutter实战视频-移动电商-53.购物车_商品列表UI框架布局

    53.购物车_商品列表UI框架布局 cart_page.dart 清空原来写的持久化的代码; 添加对应的引用,stless生成一个静态的类.建议始终静态的类,防止重复渲染 纠正个错误,上图的CartP ...

  4. 关于weblogic 10.3.6.0 的漏洞复现(2)

    今天小R又学会了一个工具的使用,而且这个工具很强大很强大. 待会介绍. 一.需要的试验环境: 一台宿主机,虚拟机(kali+window2008或其他版本的windows)  1.宿主机需要的工具:B ...

  5. 打造个人IP: 开源项目网站构建框架

    前言 您是否正在寻找有关如何创建博客网站: 个人博客 或者 开源项目官网 : Dubbo, Vue.js的构建框架? 在这篇文章我将向您展示如何创建一个美观并且实用的开源博客/开源项目官网构建框架!近 ...

  6. SCUT - 114 - 作业之数学篇 - 杜教筛

    https://scut.online/p/114 \(A(n)=\sum\limits_{i=1}^{n} \frac{lcm(i,n)}{gcd(i,n)}\) \(=\sum\limits_{i ...

  7. (水题)HDU - 1077 - Catching Fish - 计算几何

    http://acm.hdu.edu.cn/showproblem.php?pid=1077 很明显这样的圆,必定有两个点在边界上.n平方枚举圆,再n立方暴力判断.由于没有给T,所以不知道行不行.

  8. HDU5904【瞎搞】

    哇咔咔,挂完. 靠着hack的100分挂在了rank167... 就是memset的问题,超时了:用map好了.. 思路: 标记a串以当前值为尾的上升子序列长度,然后还是搞b串,每次判一下当前值在a串 ...

  9. 关于 T[] 的反射问题

    1. T[] 类型不适应以下代码 Dictionary<string, Test> d = new Dictionary<string, Test>(); // Get a T ...

  10. 51nod1416(dfs)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1416 题意:中文题诶- 思路:dfs 搜索同一颜色的点.. 只 ...