点击上方“
程序员大咖
”,选择“置顶公众号”
关键时刻,第一时间送达!
1、系统对象的复制
不管是集合类对象,还是非集合类对象,接收到copy和mutableCopy消息时,都遵循以下准则:
下图详细阐述了NSString、NSMutableString、NSArray、NSMutableArray、NSDictionary、NSMutableDictionary分别调用copy与mutableCopy方法后的结果:
1.1 非集合类对象的copy与mutableCopy
系统非集合类对象指的是NSString,NSNumber之类的对象。下面看一下非集合类NSString对象拷贝的例子:
copy
NSString *
string
=
@
"origin"
;
NSString *
stringCopy
=
[
string
copy
];
NSMutableString *
stringMCopy
=
[
string
mutableCopy
];
NSLog
(@
"%p"
,
string
);
NSLog
(@
"%p"
,
stringCopy
);
NSLog
(@
"%p"
,
stringMCopy
);
2016
-
03
-
10
17
:
32
:
04.479
Homework
[
21715
:
2353641
]
0x1000d0ea0
2016
-
03
-
10
17
:
32
:
04.481
Homework
[
21715
:
2353641
]
0x1000d0ea0
2016
-
03
-
10
17
:
32
:
04.481
Homework
[
21715
:
2353641
]
0x17006fe40
通过查看内存,可以看到stringCopy和string的地址是一样,进行了指针拷贝;而stringMCopy的地址和string不一样,进行了内容拷贝。
mutableCopy
NSMutableString *
string
=
[
NSMutableString
stringWithString
:
@
"origin"
];
//copy
NSString *
stringCopy
=
[
string
copy
];
NSMutableString *
mStringCopy
=
[
string
copy
];
NSMutableString *
stringMCopy
=
[
string
mutableCopy
];
NSLog
(@
"%p"
,
string
);
NSLog
(@
"%p"
,
stringCopy
);
NSLog
(@
"%p"
,
mStringCopy
);
NSLog
(@
"%p"
,
stringMCopy
);
2016
-
03
-
10
17
:
34
:
11.486
Homework
[
21728
:
2354359
]
0x17426f800
2016
-
03
-
10
17
:
34
:
11.487
Homework
[
21728
:
2354359
]
0x174230600
2016
-
03
-
10
17
:
34
:
11.487
Homework
[
21728
:
2354359
]
0x1742306e0
2016
-
03
-
10
17
:
34
:
11.487
Homework
[
21728
:
2354359
]
0x174267240
//change value
[
mStringCopy
appendString
:
@
"mm"
];
//crash
[
string
appendString
:
@
" origion!"
];
[
stringMCopy
appendString
:
@
"!!"
];
crash的原因就是copy返回的对象是immutable对象。
1.2 集合类对象的copy与mutableCopy
集合类对象是指NSArray、NSDictionary、NSSet之类的对象。下面看一下集合类NSArray对象使用copy和mutableCopy的一个例子:
copy
NSArray *
array
=
@[@[@
"a"
,
@
"b"
],
@[@
"c"
,
@
"d"
]];
NSArray *
copyArray
=
[
array
copy
];
NSMutableArray *
mCopyArray
=
[
array
mutableCopy
];
NSLog
(@
"%p"
,
array
);
NSLog
(@
"%p"
,
copyArray
);
NSLog
(@
"%p"
,
mCopyArray
);
2016
-
03
-
10
17
:
53
:
40.113
Homework
[
21775
:
2358227
]
0x17403f040
2016
-
03
-
10
17
:
53
:
40.114
Homework
[
21775
:
2358227
]
0x17403f040
2016
-
03
-
10
17
:
53
:
40.114
Homework
[
21775
:
2358227
]
0x174247e60
可以看到copyArray和array的地址是一样的,而mCopyArray和array的地址是不同的。说明copy操作进行了指针拷贝,mutableCopy进行了内容拷贝。但需要强调的是:此处的内容拷贝,仅仅是拷贝array这个对象,array集合内部的元素仍然是指针拷贝。这和上面的非集合immutable对象的拷贝还是挺相似的,那么mutable对象的拷贝会不会类似呢?我们继续往下,
mutableCopy
NSMutableArray *
array
=
[
NSMutableArray
arrayWithObjects
:
[
NSMutableString
stringWithString
:
@
"a"
],@
"b"
,@
"c"
,
nil
];
NSArray *
copyArray
=
[
array
copy
];
NSMutableArray *
mCopyArray
=
[
array
mutableCopy
];
NSLog
(@
"%p"
,
array
);
NSLog
(@
"%p"
,
copyArray
);
NSLog
(@
"%p"
,
mCopyArray
);
2016
-
03
-
10
17
:
54
:
39.114
Homework
[
21782
:
2358605
]
0x170058e40
2016
-
03
-
10
17
:
54
:
39.115
Homework
[
21782
:
2358605
]
0x170058ed0
2016
-
03
-
10
17
:
54
:
39.115
Homework
[
21782
:
2358605
]
0x170058ea0
查看内存,如我们所料,copyArray、mCopyArray和array的内存地址都不一样,说明copyArray、mCopyArray都对array进行了内容拷贝。
2、自定义对象的复制
使用copy和mutableCopy复制对象的副本使用起来确实方便,那么我们自定义的类是否可调用copy与mutableCopy方法来复制副本呢?我们先定义一个Person类,代码如下:
@
interface
Person
:
NSObject
@
property
(
nonatomic
,
assign
)
NSInteger
age
;
@
property
(
nonatomic
,
copy
)
NSString *
name
;
@
end
然后尝试调用Person的copy方法来复制一个副本:
Person *
person1
=
[[
Person
alloc
]
init
];
//创建一个Person对象
person1
.
age
=
20
;
person1
.
name
=
@
"张三"
;
Person *
person2
=
[
person1
copy
];
//复制副本
运行程序,将会发生崩溃,并输出以下错误信息:
[
Person
copyWithZone
:
]
:
unrecognized selector sent
to
instance
0x608000030920
上面的提示:Person找不到copyWithZone:方法。我们将复制副本的代码换成如下:
Person *
person2
=
[
person1
mutableCopy
];
//复制副本
再次运行程序,程序同样崩溃了,并输出去以下错误信息:
[
Person
mutableCopyWithZone
:
]
:
unrecognized selector sent
to
instance
0x600000221120
上面的提示:Person找不到mutableCopyWithZone:方法。
大家可能会觉得疑惑,程序只是调用了copy和mutableCopy方法,为什么会提示找不到copyWithZone:与mutableCopyWithZone:方法呢?其实当程序调用对象的copy方法来复制自身时,底层需要调用copyWithZone:方法来完成实际的复制工作,copy返回实际上就是copyWithZone:方法的返回值;mutableCopy与mutableCopyWithZone:方法也是同样的道理。
那么怎么做才能让自定义的对象进行copy与mutableCopy呢?需要做以下事情:
1.
让类实现
NSCopying
/
NSMutableCopying
协议。
2.
让类实现
copyWithZone
:/
mutableCopyWithZone
:
方法
所以让我们的Person类能够复制自身,我们需要让Person实现NSCopying协议;然后实现copyWithZone:方法:
@
interface
Person
:
NSObject
@
property
(
nonatomic
,
assign
)
NSInteger
age
;
@
property
(
nonatomic
,
copy