复制对象(一)copy和mutableCopy方法

本文转载至 http://www.tuicool.com/articles/Fn6rMn

CSDN博客原文  http://blog.csdn.net/u010962810/article/details/18887841

通过copy方法可以创建可变对象或不可变对象的不可变副本,对于不可变副本,其对象的值不可以改变。

通过mutableCopy方法可以创建可变对象或不可变对象的可变副本,对于可变副本其对象是可变的。

复制分为浅复制和深复制两种:浅复制只是复制对象的引用,并没有复制对象的具体内容。深复制则创建了要复制对象的具体内容,并返回对象副本的引用。

对于复制Foundation中的对象,默认并不是深复制,例如copy NSMutableArray对象是浅复制,只是对其引用进行复制;而copy NSMutableString对象是深复制,对原来引用的对象的具体内容也进行了复制。

1.NSMutableArray和NSArray

首先创建1个数组(该数组中有3个对象)和4个数组指针:

NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
                                   [NSMutableString stringWithString:@"1"],
                                   [NSMutableString stringWithString:@"2"],
                                   [NSMutableString stringWithFormat:@"3"],
                                   nil];
        NSMutableArray *marray2 = [marray1 mutableCopy];
        NSArray *array1 = [marray1 copy];
        NSArray *array2 = [marray1 mutableCopy];

(1)添加字符串到marray1[0]中:

// append string to marray1[0]
        NSMutableString *mstr = marray1[0];
        [mstr appendString:@" append"];
        NSLog(@"append string to marray1[0]");
        NSLog(@"marray1 = %@", marray1);
        NSLog(@"marray2 = %@", marray2);
        NSLog(@"array1 = %@", array1);
        NSLog(@"array2 = %@", array2);
2014-01-31 21:10:39.097 Array[298:303] append string to marray1[0]
2014-01-31 21:10:39.098 Array[298:303] marray1 = (
    "1 append",
    2,
    3
)
2014-01-31 21:10:39.098 Array[298:303] marray2 = (
    "1 append",
    2,
    3
)
2014-01-31 21:10:39.098 Array[298:303] array1 = (
    "1 append",
    2,
    3
)
2014-01-31 21:10:39.099 Array[298:303] array2 = (
    "1 append",
    2,
    3
)

分析:

假设marray1中保存的是obj1,obj2,obj3组成的数组的首地址。将marray1复制给marray2,array1和array2,只是将指向数组第一个对象的内存地址复制到marray2等数组指针中保存。

在marray1[0]指向的对象obj1后面附加字符串append,由于marray1,marray2,array1和array2第一个指针指向的对象都是obj1,所以输出一致。

这里的copy方法和简单的赋值作用是一致的。

(2)为marray1[0]设置新的对象值:(注意(2)、(3)和(1)是相互独立的,下同)

// set new object to marray1[0]
        marray1[0] = [NSMutableString stringWithString:@"new 1"];
        NSLog(@"set new object to marray1[0]");
        NSLog(@"marray1 = %@", marray1);
        NSLog(@"marray2 = %@", marray2);
        NSLog(@"array1 = %@", array1);
        NSLog(@"array2 = %@", array2);
2014-01-31 20:50:52.003 Array[4151:303] set new object to marray1[0]
2014-01-31 20:50:52.004 Array[4151:303] marray1 = (
    "new 1",
    2,
    3
)
2014-01-31 20:50:52.005 Array[4151:303] marray2 = (
    1,
    2,
    3
)
2014-01-31 20:50:52.005 Array[4151:303] array1 = (
    1,
    2,
    3
)
2014-01-31 20:50:52.005 Array[4151:303] array2 = (
    1,
    2,
    3
)

分析:

这里创建了一个新的NSMutableString对象将其引用赋给marray1[0],而其他数组指针指向的对象不变,所以输出时其他数组不受影响。

(3)添加新的对象到marray1中:

// add new object to marray1
        [marray1 addObject:[NSMutableString stringWithString:@"4"]];
        NSLog(@"add new object to marray1");
        NSLog(@"marray1 = %@", marray1);
        NSLog(@"marray2 = %@", marray2);
        NSLog(@"array1 = %@", array1);
        NSLog(@"array2 = %@", array2);
2014-01-31 20:51:46.867 Array[4167:303] add new object to marray1
2014-01-31 20:51:46.869 Array[4167:303] marray1 = (
    1,
    2,
    3,
    4
)
2014-01-31 20:51:46.869 Array[4167:303] marray2 = (
    1,
    2,
    3
)
2014-01-31 20:51:46.869 Array[4167:303] array1 = (
    1,
    2,
    3
)
2014-01-31 20:51:46.869 Array[4167:303] array2 = (
    1,
    2,
    3
)

分析:

这里创建了一个新的可变字符串对象,并将其内存地址保存到指针marray1[3]中。而其他几个数组指针的引用不受影响。

(4)操作数组的引用

如果要单独替换marray1[0]指向的对象,应该先创建一个对象,然后再替换marray1[0]的引用。这样就不会对marray2[0]指向的对象造成影响。

NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
                                   [NSMutableString stringWithString:@"1"],
                                   [NSMutableString stringWithString:@"2"],
                                   [NSMutableString stringWithFormat:@"3"],
                                   nil];
        NSMutableArray *marray2 = [marray1 mutableCopy];
        NSArray *array1 = [marray1 copy];
        NSArray *array2 = [marray1 mutableCopy];
        NSMutableString *mstr = [NSMutableString stringWithString:marray1[0]]; // 创建新的对象
        [mstr appendString:@" append"];
        [marray1 replaceObjectAtIndex:0 withObject:mstr]; // 替换marray1[0]的引用

        NSLog(@"marray1 = %@", marray1);
        NSLog(@"marray2 = %@", marray2);
        NSLog(@"array1 = %@", array1);
        NSLog(@"array2 = %@", array2);

控制台输出:

2014-01-31 20:09:33.678 Dictionary[3735:303] marray1 = (
    "1 append",
    2,
    3
)
2014-01-31 20:09:33.679 Dictionary[3735:303] marray2 = (
    1,
    2,
    3
)
2014-01-31 20:09:33.680 Dictionary[3735:303] array1 = (
    1,
    2,
    3
)
2014-01-31 20:09:33.680 Dictionary[3735:303] array2 = (
    1,
    2,
    3
)

再看一个例子:

NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
                                   [NSMutableString stringWithString:@"1"],
                                   [NSMutableString stringWithString:@"2"],
                                   [NSMutableString stringWithFormat:@"3"],
                                   nil];
        NSMutableArray *marray2 = [marray1 mutableCopy];
        NSArray *array1 = [marray1 copy];
        NSArray *array2 = [marray1 mutableCopy];

        [marray1 removeObjectAtIndex:0];

        NSLog(@"marray1 = %@", marray1);
        NSLog(@"marray2 = %@", marray2);
        NSLog(@"array1 = %@", array1);
        NSLog(@"array2 = %@", array2);

控制台输出:

2014-01-31 20:10:40.716 Dictionary[3746:303] marray1 = (
    2,
    3
)
2014-01-31 20:10:40.717 Dictionary[3746:303] marray2 = (
    1,
    2,
    3
)
2014-01-31 20:10:40.717 Dictionary[3746:303] array1 = (
    1,
    2,
    3
)
2014-01-31 20:10:40.718 Dictionary[3746:303] array2 = (
    1,
    2,
    3
)

尽管marray1,marray2,array1,array2指向同一个数组对象,但是[marray1 removeObjectAtIndex:0]移除的是marray1第一个元素,即移除的是对对象的引用,而不是移除数组中的第一个对象。所以不会影响到marray2  ,array1,array2 。

2.NSMutableString和NSString

复制NSMutableString对象测试代码如下:

NSMutableString *mstr1 = [NSMutableString stringWithString:@"1"];
        NSMutableString *mstr2 = [mstr1 mutableCopy];
        NSString *str1 = [mstr1 copy];
        NSString *str2 = [mstr1 mutableCopy];

        [mstr1 appendString:@" append"];
        NSLog(@"mstr1 = %@", mstr1);
        NSLog(@"mstr2 = %@", mstr2);
        NSLog(@"str1 = %@", str1);
        NSLog(@"str2 = %@", str2);
2014-01-31 20:54:20.423 String[4221:303] mstr1 = 1 append
2014-01-31 20:54:20.424 String[4221:303] mstr2 = 1
2014-01-31 20:54:20.424 String[4221:303] str1 = 1
2014-01-31 20:54:20.424 String[4221:303] str2 = 1

分析:

对mstr1指向的对象STRING1进行复制,这里复制的是对象  STRING1 本身的内容,也就是mstr2,str1,str2将分别指向对象  STRING2,STRING3,STRING4,对STRING1的修改(在后面附加字符串),将不会影响到其他几个引用指向的对象。

可见这里进行的是深复制。

注意不要改变copy后的对象的值,因为copy生成的对象是不可变的,强行修改会导致程序崩溃。

控制台输出为:

2014-02-01 00:57:24.903 Array[792:303] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException‘, reason: ‘Attempt to mutate immutable object with appendString:‘

3.NSMutableDictionary和NSDictionary

首先创建1个字典(字典中对应3个对象)和4个字典指针:

NSMutableString *obj1 = [NSMutableString stringWithString:@"obj1"];
        NSMutableString *obj2 = [NSMutableString stringWithString:@"obj2"];
        NSMutableString *obj3 = [NSMutableString stringWithString:@"obj3"];
        NSMutableDictionary *mdic1 = [NSMutableDictionary dictionaryWithObjects:@[obj1, obj2, obj3]
                                                                        forKeys:@[@"key1", @"key2", @"key3"]];
        NSMutableDictionary *mdic2 = [mdic1 mutableCopy];
        NSDictionary *dic1 = [mdic1 copy];
        NSDictionary *dic2 = [mdic1 copy];

假设指针mdic1的索引key1,key2,key3分别对应对象obj1,obj2,obj3的内存地址。

对字典进行复制也是浅复制。

对mdic1复制,并赋值给mdic2,dic1,dic2,那么mdic2,dic1,dic2中指向的是同一个字典。

(1)添加字符串到mdic1的key1对应的可变字符串对象后:

// append string to mdic1[@"key1"]
        NSMutableString *mstr = mdic1[@"key1"];
        [mstr appendString:@" append"];
        NSLog(@"append string to midc1[@\"key1\"]");
        NSLog(@"mdic1 = %@", mdic1);
        NSLog(@"mdic2 = %@", mdic2);
        NSLog(@"dic1 = %@", dic1);
        NSLog(@"dic2 = %@", dic2);
2014-01-31 22:07:29.241 Dictionary[431:303] append string to midc1[@"key1"]
2014-01-31 22:07:29.242 Dictionary[431:303] mdic1 = {
    key1 = "obj1 append";
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:07:29.243 Dictionary[431:303] mdic2 = {
    key1 = "obj1 append";
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:07:29.243 Dictionary[431:303] dic1 = {
    key1 = "obj1 append";
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:07:29.243 Dictionary[431:303] dic2 = {
    key1 = "obj1 append";
    key2 = obj2;
    key3 = obj3;
}

上面代码中对key1对应的对象obj1进行修改(在对象后面附加字符串),由于mdic2等指向同一个字典,所以其输出将会和mdic1的输出一致。

(2)设置新的对象给key1:

// set new object for  key1
        NSMutableString *nobj1 = [NSMutableString stringWithString:@"new obj1"];
        [mdic1 setObject:nobj1 forKey:@"key1"];
        NSLog(@"set new object for key");
        NSLog(@"mdic1 = %@", mdic1);
        NSLog(@"mdic2 = %@", mdic2);
        NSLog(@"dic1 = %@", dic1);
        NSLog(@"dic2 = %@", dic2);
2014-01-31 22:08:01.617 Dictionary[448:303] set new object for key
2014-01-31 22:08:01.618 Dictionary[448:303] mdic1 = {
    key1 = "new obj1";
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:08:01.619 Dictionary[448:303] mdic2 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:08:01.619 Dictionary[448:303] dic1 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:08:01.619 Dictionary[448:303] dic2 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
}

这里只是修改了mdic1的索引key1中保存的内存地址,并不会对其他引用所指向的对象造成影响。

(3)在字典中添加新的key-value对:

// add new key-value
        NSMutableString *obj4 = [NSMutableString stringWithString:@"obj4"];
        [mdic1 setObject:obj4 forKey:@"key4"];
        NSLog(@"add new key-value");
        NSLog(@"mdic1 = %@", mdic1);
        NSLog(@"mdic2 = %@", mdic2);
        NSLog(@"dic1 = %@", dic1);
        NSLog(@"dic2 = %@", dic2);
2014-01-31 22:12:14.678 Dictionary[466:303] add new key-value
2014-01-31 22:12:14.679 Dictionary[466:303] mdic1 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
    key4 = obj4;
}
2014-01-31 22:12:14.679 Dictionary[466:303] mdic2 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:12:14.679 Dictionary[466:303] dic1 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
}
2014-01-31 22:12:14.680 Dictionary[466:303] dic2 = {
    key1 = obj1;
    key2 = obj2;
    key3 = obj3;
}

现在为mdic1对应的字典添加新的key-value对,这不会影响到其他字典指针,所以输出不受影响。

小结:

1.浅复制复制的是对象的引用,对指针的修改并不会影响到指向的对象,更不会影响到其他指针。 深复制复制的是对象的内容,对对象的操作修改将影响到所有指向该对象的引用。

2.NSMutableArray和NSMutableDictionary的复制是浅复制,NSMutableString的复制是深复制。由于数组或字典中对象数目或大小可能非常大,所以对对象的复制可能引起大量开销,因此这里只复制引用可以节省开销。

时间: 2024-11-10 13:33:28

复制对象(一)copy和mutableCopy方法的相关文章

Objective-c中对象的Copy、MutableCopy、浅拷贝、深拷贝

对象的复制就是复制一个对象作为副本,他会开辟一块新的内存(堆内存)来存储副本对象,就像复制文件一样,即源对象和副本对象是两块不同的内存区域.对象要具备复制功能,必须实现<NSCopying>协议或者<NSMutableCopying>协议,常用的可复制对象有:NSNumber.NSString.NSMutableString.NSArray.NSMutableArray.NSDictionary.NSMutableDictionary copy:产生对象的副本是不可变的 mutab

关于:1.指针与对象;2.深浅拷贝(复制);3.可变与不可变对象;4.copy与mutableCopy的一些理解

最近对深浅拷贝(复制)做了一些研究,在此将自己的理解写下来,希望对大家有所帮助.本人尚处在摸索阶段,希望各位予以指正. 本文包括如下方向的探索: 1.指针与对象: 2.深/浅拷贝(复制): 3.可变/不可变对象: 4.Objective-C中的copy与mutableCopy方法. 一.指针与对象 在初始学习编程的时候,对于绝大多数面向对象编程的语言,这都是个绕不开的重点与难点.非常惭愧的是对它的认识我一直是不够的,并且感觉这项技术有许多的内容可以挖掘.说这是面向对象编程的核心思想也不为过.很多

探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法

NSString: 1 //main.m 2 #import <Foundation/Foundation.h> 3 4 int main(int argc, const char * argv[]) { 5 @autoreleasepool { 6 7 NSString *str1 = @"aaa"; 8 NSString *str2 ; 9 NSString *str3 ; 10 NSString *str4 ; 11 NSString *str5 ; 12 NSStr

Copy和MutableCopy

//    一: copy 与 retain 的区别 //    谁才有引用计数的概念: //    1. 堆区空间才有引用计数概念. //    2. 堆区的对象才会有引用计数. //%ld: - 1           %lu:18446744073709551615 //retain:始终是浅拷贝.引用计数每次加一. //返回对象是否可变与被复制的对象保持一致. //copy:对于可变对象为深拷贝,引用计数不改变; //对于不可变对象是浅拷贝,引用计数每次加一. //始终返回一个不可变对象

[学习笔记—Objective-C]《Objective-C 程序设计 第6版》第十八章 复制对象

origin = pt; 将对象pt的地址复制到origin中.两个变量都指向内存中同一个地址 Foundation对象:将一个变量赋值给另一个对象仅仅创建了另一个对这个对象的引用(地址). Part 1.copy 和 mutablecopy 方法:创建对象的副本 复制对象(的引用) dataArray2 = dataArray;//创建了内存中同一数组对象的另一个引用:总共一个数组 创建对象的副本 dataArray2 = [dataArray mutalbeCopy];//创建信的dataA

copy 与 retain的区别,以及copy与mutablecopy的区别

copy 与 retain的区别 copy: 建立一个索引计数为1的对象,然后释放旧对象      retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 Copy其实是建立了一个相同的对象,而retain不是:比如一个NSString对象,地址为0×1111,内容为@”STR”, Copy到另外一个NSString之 后,地址为0×2222,内容相同,新的对象retain为1, 旧有对象没有变化 而retain到另外一个NSString之 后,地址相同(建立一个指针

objective-c 复制对象

对象的复制有深复制和浅复制两种,听上去高大上会很难,其实很简单: 来举个例子: NSMutableArray * array1 = [NSMutableArray arrayWithObjects:@"a" ,@"b", nil]; NSMutableArray *array2 = array1; [array2 addObject:@"c"]; for(NSString *s in array1) { NSLog(@"%@"

copy和mutableCopy的使用

一个对象使用copy或mutableCopy方法可以创建对象的副本 copy - 需要先实现NSCopying协议,创建的是不可变副本(如NSString, NSArray, NSDictionary) mutableCopy - 需要先实现NSMutableCopying协议,创建的是可变副本(如NSMutableString,NSMutableArray, NSMutableDictionary) 深复制:内容拷贝,源对象和副本指向的是不同的两个对象,源对象引用计数器不变,副本计数器设置为1

copy 和 mutablecopy 笔记

作者:高笑228 | 出处:博客园 | 2012/4/22 14:53:20 | 阅读4次 NSString *a = [[NSString alloc]initWithString:@"hello"];    NSString *b = [a copy];    NSLog(@"%d   %d",a.retainCount, b.retainCount);// 2,2        NSMutableString *f = [a mutableCopy];