IOS ObjectiveC中的赋值与对象拷贝

IOS ObjectiveC中的赋值与对象拷贝

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

一、不同对象的赋值操作

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

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

// main.m 

#import <Foundation/Foundation.h> 

@interface TestObject : NSObject
{
  @public
  int x;
  int y;
}
@end 

@implementation TestObject
@end 

typedef struct TestStruct
{
  int x;
  int y;
}
TestStruct; 

int main(int argc, const char * argv[])
{ 

  @autoreleasepool { 

    TestStruct ts1 = {100, 50};
    NSLog(@"ts1: %p, %d, %d", &ts1, ts1.x, ts1.y); 

    TestStruct ts2 = ts1;
    NSLog(@"ts2: %p, %d, %d", &ts2, ts2.x, ts2.y); 

    TestObject* to1 = [[[TestObject alloc] init] autorelease];
    NSLog(@"to1: %p, %d, %d", to1, to1->x, to1->y); 

    TestObject* to2 = to1;
    NSLog(@"to2: %p, %d, %d", to2, to2->x, to2->y); 

  }
  return 0;
}

程序的运行结果如下:

ts1: 0x7fff63463898, 100, 50
ts2: 0x7fff63463890, 100, 50
to1: 0x7fc342d00370, 0, 0
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:方法。将上面的代码修改如下:

#import <Foundation/Foundation.h> 

@interface TestObject : NSObject
{
  @public
  int x;
  int y;
}
@end 

@implementation TestObject
- (NSString*)description
{
  return [NSString stringWithFormat:@"%@: %p, x: %d, y: %d", [self class], self, x, y];
}
@end 

typedef struct TestStruct
{
  int x;
  int y;
}
TestStruct; 

int main(int argc, const char * argv[])
{
  @autoreleasepool
  {
    TestObject* to1 = [[[TestObject alloc] init] autorelease];
    to1->x = 100; to1->y = 50;
    TestObject* to2 = [[[TestObject alloc] init] autorelease];
    to2->x = 200; to2->y = 400;
    TestObject* to3 = [[[TestObject alloc] init] autorelease];
    to3->x = 300; to3->y = 500; 

    //创建包含to1, to2, to3的数组array1
    NSArray* array1 = [NSArray arrayWithObjects:to1, to2, to3, nil];
    NSLog(@"array1: %p, \n%@", array1, array1); 

    //array2是array1调用copy的结果
    NSArray* array2 = [array1 copy];
    NSLog(@"array2: %p, \n%@", array2, array2);
    [array2 release]; 

    //mutableArray2是array1调用mutableCopy的结果
    NSMutableArray* mutableArray2 = [array1 mutableCopy];
    NSLog(@"mutableArray2: %@, %p, \n%@", [mutableArray2 class], mutableArray2, mutableArray2);
    [mutableArray2 removeLastObject]; 

    NSLog(@"After remove last object of mutableArray2"); 

    NSLog(@"array1: %p, \n%@", array1, array1);
    NSLog(@"array2: %p, \n%@", array2, array2);
    NSLog(@"mutableArray2: %p, \n%@", mutableArray2, mutableArray2); 

    //mutableArray3是mutableArray2调用mutableCopy的结果
    NSMutableArray* mutableArray3 = [mutableArray2 mutableCopy];
    NSLog(@"mutableArray3: %p, \n%@", mutableArray3, mutableArray3);
    [mutableArray2 release]; 

    //array4是mutableArray3调用copy的结果
    NSArray* array4 = [mutableArray3 copy];
    NSLog(@"array4: %@, %p, \n%@", [array4 class], array4, array4);
    [mutableArray3 release];
    [array4 release];
  }
  return 0;
}

程序的运行结果如下:

2012-03-22 19:20:49.548 ObjectCopy[18042:403] array1: 0x7f9071414820,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400",
  "TestObject: 0x7f9071414230, x: 300, y: 500"
)
2012-03-22 19:20:49.550 ObjectCopy[18042:403] array2: 0x7f9071414820,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400",
  "TestObject: 0x7f9071414230, x: 300, y: 500"
)
2012-03-22 19:20:49.551 ObjectCopy[18042:403] mutableArray2: __NSArrayM, 0x7f9072800000,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400",
  "TestObject: 0x7f9071414230, x: 300, y: 500"
)
2012-03-22 19:20:49.552 ObjectCopy[18042:403] After remove last object of mutableArray2
2012-03-22 19:20:49.552 ObjectCopy[18042:403] array1: 0x7f9071414820,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400",
  "TestObject: 0x7f9071414230, x: 300, y: 500"
)
2012-03-22 19:20:49.553 ObjectCopy[18042:403] array2: 0x7f9071414820,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400",
  "TestObject: 0x7f9071414230, x: 300, y: 500"
)
2012-03-22 19:20:49.553 ObjectCopy[18042:403] mutableArray2: 0x7f9072800000,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400"
)
2012-03-22 19:20:49.557 ObjectCopy[18042:403] mutableArray3: 0x7f90729000d0,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400"
)
2012-03-22 19:20:49.558 ObjectCopy[18042:403] array4: __NSArrayI, 0x7f9071416e70,
(
  "TestObject: 0x7f90714141b0, x: 100, y: 50",
  "TestObject: 0x7f90714141c0, x: 200, y: 400"
)

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

第四,在NSArray对象上调用mutableCopy方法返回一个NSMutableArray对象,而在NSMutableArray对象上调用copy方法则返回一个NSArray对象,而不是NSMutableArray对象。

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

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • 浅析iOS中的浅拷贝和深拷贝(copy和mutableCopy)

    ios提供了copy和mutablecopy方法,顾名思义,copy就是复制了一个imutable的对象,而mutablecopy就是复制了一个mutable的对象. copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化.copy减少对象对上下文的依赖. retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的

  • 详解iOS的深浅拷贝

    前言 OC对象的三种拷贝方式 OC的对象拷贝有如下三种方式,很多时候我们把深复制和完全复制混为一谈,其他他们是有区别的,具体如下 浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制. 深复制(one-level-deep copy):在深复制操作时,对于被复制对象,至少有一层是深复制. 完全复制(real-deep copy):在完全复制操作时,对于被复制对象的每一层都是对象复制. 两图以避之 理解深复制(mutableCopy) 浅复制很简单,就不演示了,看

  • IOS ObjectiveC中的赋值与对象拷贝

    IOS ObjectiveC中的赋值与对象拷贝 在开发过程中我们经常会遇到对象拷贝的问题,下面我们分别讨论赋值操作.对象拷贝.以及浅拷贝(Shallow copy)与深拷贝(Deep copy)的区别与各自的实现方式. 一.不同对象的赋值操作 Objective-C中有两类对象,一类是结构体(或者基本数据类型也算),另一类是NSObject对象. 对于结构体,代码直接会操作其实体,因此赋值操作会创建一个源对象的副本(一个新的对象):而对于NSObject对象,必须使用指针来操作对象,所以其赋值操

  • 浅析Python中的赋值和深浅拷贝

    python中,A object  = B object  是一种赋值操作,赋的值不是一个对象在内存中的空间,而只是这个对象在内存中的位置 . 此时当B对象里面的内容发生更改的时候,A对象也自然而然的会跟着更改. name = ["root","admin"] cp_name = name # 对cp_name进行赋值操作 # 对name列表进行插入 name.append('root_temp') print(name,cp_name) # ['root', 'a

  • JavaScript对象拷贝与赋值操作实例分析

    本文实例讲述了JavaScript对象拷贝与赋值操作.分享给大家供大家参考,具体如下: 今天在做公司面试题的时候,遇到了一道关于JavaScript之对象拷贝与赋值的问题,突然觉得很有意义,想和大家一起来分享一下! 首先,先摆出代码,如下: /** * Created by Administrator on 2016/12/7. */ var obj={ name:"dahuang", age:10 } var newObj=obj; newObj.name="xiaohua

  • iOS开发中runtime常用的几种方法示例总结

    前言 Objective-C runtime是一个实现Objective-C语言的C库.它是一门编译型语言.也是一门动态型的语言(这里强调下OC是静态类型语言),之前没接触runtime的时候也不觉着它有多重要,接触之后才发现其实runtime挺强大的.就拿我们在iOS开发中所使用的OC编程语言来讲,OC之所以能够做到即是编译型语言,又能做到动态语言,就是得益于runtime的机制. 最近公司项目中用了一些 runtime 相关的知识, 初看时有些蒙, 虽然用的并不多, 但还是想着系统的把 ru

  • iOS开发中使用UIScrollView实现无限循环的图片浏览器

    一.概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授人以渔,这里会尽可能让大家明白其中的原理,找一些典型的控件进行说明,这样一来大家就可以触类旁通.今天我们主要来看一下UIScrollView的内容: UIView UIScrollView 实战--图片浏览器 二.UIView 在熟悉UIScrollView之前很有必要说一下UIView的内容.

  • iOS开发中CALayer使用的基本教程

    一.简单介绍 在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮.一个文本标签.一个文本输入框.一个图标等等,这些都是UIView. 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层,在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个层 @property(nonatomic,readonly,retain) CALayer *layer; 当UIView需要显示到屏幕上时,会调用

  • IOS Object-C 中Runtime详解及实例代码

    IOS Object-C 中Runtime详解 最近了解了一下OC的Runtime,真的是OC中很强大的一个机制,看起来比较底层,但其实可以有很多活用的方式. 什么是Runtime 我们虽然是用Objective-C写的代码,其实在运行过程中都会被转化成C代码去执行.比如说OC的方法调用都会转成C函数 id objc_msgSend ( id self, SEL op, - ); 而OC中的对象其实在Runtime中都会用结构体来表示,这个结构体中包含了类名.成员变量列表.方法列表.协议列表.缓

  • Objective-C中常用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect实例分析

    本文以实例详细描述了Objective-C中常用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect的定义及用法,具体如下所示: 1.NSRange: NSRange的原型为 typedef struct _NSRange { NSUInteger location; NSUInteger length; } NSRange; NSMakeRange的函数: NS_INLINEz是内联函数 typedef NSRange *NSRangePointer; NS_IN

  • java对象拷贝详解及实例

    java对象拷贝详解及实例 Java赋值是复制对象引用,如果我们想要得到一个对象的副本,使用赋值操作是无法达到目的的: @Test public void testassign(){ Person p1=new Person(); p1.setAge(31); p1.setName("Peter"); Person p2=p1; System.out.println(p1==p2);//true } 如果创建一个对象的新的副本,也就是说他们的初始状态完全一样,但以后可以改变各自的状态,

  • 简述iOS属性中的内存管理参数

    一,assign 代表设置时候直接赋值,而不是复制或者保留它. 二,retain. 会在赋值的时候把新值保留.此属性只能用于Object-C对象类型. 三,copy 在赋值时,将新值复制一份,复制工作由copy执行,此属性只对那些实行了NSCopying协议的对象类型有效. 总结 以上所述是小编给大家介绍的iOS属性中的内存管理参数 ,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的! 您可能感兴趣的文章: 详解关于iOS内存管理的规则思考 详解iOS应用开发中的ARC内

随机推荐