本文主要參考:
http://www.reibang.com/p/8080bbae0acc如有侵權(quán)但骨,告知我撤銷道逗。
iOS開發(fā)中砂沛,不是所有的對象都支持copy、mutableCopy哀澈。
遵守NSCopying協(xié)議的類可以發(fā)送copy消息牌借,遵守NSMutableCopying協(xié)議的類才可以發(fā)送mutablecopy消息。
顧名思義日丹,copy就是復(fù)制了一個imutable(非容器類)的對象走哺,而mutablecopy(容器類)就是復(fù)制了一個mutable的對象蚯嫌。
一哲虾、非集合類對象(如NSString、NSNumber)
1择示、非容器類對象(如NSString束凑、NSNumber等一類的對象)
總結(jié):對一個iMutable(非容器)的非集合類對象string:
調(diào)copy方法,其實復(fù)制的是string對象指向那塊內(nèi)存地址的指針栅盲,是指針拷貝汪诉,string 和stringCopy都是指向的同一塊內(nèi)存地址。(淺拷貝)
調(diào)mutableCopy方法,復(fù)制的是string對象指向的那塊內(nèi)存地址的內(nèi)容扒寄,是內(nèi)容拷貝鱼鼓,stringMutableCopy重新指向一塊內(nèi)存地址,而這個內(nèi)存地址保存的內(nèi)容是從string指向的內(nèi)存地址復(fù)制過來的,stringMutableCopy是一個可變對象该编。(深拷貝)
2迄本、容器類對象(如NSMutableString、NSMutableNumber等一類的對象)
總結(jié):對一個mutable的非集合類對象mutableString课竣,
調(diào)copy方法嘉赎,復(fù)制的是mutableString對象指向的那塊內(nèi)存地址的內(nèi)容,是內(nèi)容拷貝于樟,但是得到的mutableStringCopy對象是一個不可變對象公条。
調(diào)mutableCopy方法,是內(nèi)容拷貝迂曲,且得到的mutableStringMutableCopy對象是一個可變對象
非集合類總結(jié):在非集合類對象中靶橱,對immutable對象進行copy操作,是指針復(fù)制路捧,mutableCopy操作時內(nèi)容復(fù)制抓韩;對mutable對象進行copy和mutableCopy都是內(nèi)容復(fù)制。用代碼簡單表示如下:
[immutableObject copy] // 淺復(fù)制
[immutableObject mutableCopy] //深復(fù)制
[mutableObject copy] //深復(fù)制
[mutableObject mutableCopy] //深復(fù)制
二鬓长、集合類對象(如NSDictionary谒拴、NSArray、NSSet一類的對象)
總結(jié):copy操作進行了指針拷貝涉波,mutableCopy進行了內(nèi)容拷貝英上。但需要強調(diào)的是:此處的內(nèi)容拷貝,僅僅是拷貝array這個對象啤覆,array集合內(nèi)部的元素仍然是指針拷貝苍日。
arrayCopy和array是指針復(fù)制,是同一個NSArray對象(指向相同的對象)窗声,包括array里面的元素也是指向相同的指針
mutableArrayCopy是兌現(xiàn)復(fù)制相恃,是array的可變副本,指向的對象和array不同笨觅。但是其中的元素和array中的元素指向的是同一個對象拦耐。mutableArrayCopy還可以修改自己的對象。
[mutableArrayCopy addObject:@“de”];
[mutableArrayCopy removeObjectAtIndex:0];//注意见剩,容器內(nèi)的元素內(nèi)容都是指針復(fù)制杀糯。
對于容器,其元素對象始終是指針復(fù)制苍苞。如果需要元素對象也是對象復(fù)制固翰,就需要實現(xiàn)深拷貝:
trueDeepCopyArray是完全意義上的深拷貝,而deepCopyArray則不是,對于deepCopyArray內(nèi)的不可變元素其還是指針復(fù)制骂际×屏穑或者我們自己實現(xiàn)深拷貝的方法。因為如果容器的某一元素是不可變的歉铝,那你復(fù)制完后該對象仍舊是不能改變的没炒,因此只需要指針復(fù)制即可。除非你對容器內(nèi)的元素重新賦值犯戏,否則指針復(fù)制即已足夠送火。舉個例子,[[array objectAtIndex:0] appendstring:@”sd”]后其他的容器內(nèi)對象并不會受影響先匪。[[array objectAtIndex:1]和[[deepCopyArray objectAtIndex:0]盡管是指向同一塊內(nèi)存种吸,但是我們沒有辦法對其進行修改——因為它是不可改變的。所以指針復(fù)制已經(jīng)足夠呀非。
內(nèi)存地址不一樣坚俗,說明對于mutable Array,調(diào)copy和調(diào)mutable方法都是進行內(nèi)容拷貝,array集合內(nèi)部的元素仍然是指針拷貝
二岸裙、自定義對象
當(dāng)然在 ios 中并不是所有的對象都支持copy猖败,mutableCopy,遵守NSCopying協(xié)議的類可以發(fā)送copy消息降允,遵守NSMutableCopying協(xié)議的類才可以發(fā)送mutableCopy消息恩闻。
假如發(fā)送了一個沒有遵守上述兩協(xié)議而發(fā)送copy或者 mutableCopy,那么就會發(fā)生異常。但是默認(rèn)的ios類并沒有遵守這兩個協(xié)議剧董。如果想自定義一下copy那么就必須遵守NSCopying,并且實現(xiàn) copyWithZone:方法幢尚,如果想自定義一下mutableCopy那么就必須遵守NSMutableCopying,并且實現(xiàn) mutableCopyWithZone:方法。
@interface Copy : NSObject<NSCopying,NSMutableCopying>
{
NSMutableString *name;
NSString *imutableStr;
int age;
}
@property (nonatomic, retain) NSMutableString *name;
@property (nonatomic, retain) NSString *imutableStr;
@property (nonatomic) int age;
@end
@implementation Copy
@synthesize name;
@synthesize age;
@synthesize imutableStr;
- (id)init
{
if (self = [super init])
{
self.name = [[NSMutableString alloc]init];
self.imutableStr = [[NSString alloc]init];
age = -1;
}
return self;
} - (void)dealloc
{
[name release];
[imutableStr release];
[super dealloc];
} - (id)copyWithZone:(NSZone *)zone
{
MyObj *copy = [[[self class] allocWithZone:zone] init];
copy->name = [name copy];
copy->imutableStr = [imutableStr copy];
// copy->name = [name copyWithZone:zone];;
// copy->imutableStr = [name copyWithZone:zone];//
copy->age = age;
return copy;
} - (id)mutableCopyWithZone:(NSZone *)zone
{
MyObj *copy = NSCopyObject(self, 0, zone);
copy->name = [self.name mutableCopy];
copy->age = age;
return copy;
}
@end
四翅楼。屬性修飾符相關(guān)
如果property是NSString或NSArray及其子類的時候尉剩,最好選擇使用copy。為什么毅臊?
這是為了防止賦值給它的是可變的數(shù)據(jù)理茎,如果可變的數(shù)據(jù)發(fā)生了變化,那么該property也會發(fā)生變化管嬉。
@interface Person : NSObject
@property (strong, nonatomic) NSArray *bookArray1;
@property (copy, nonatomic) NSArray *bookArray2;
@end
@implementation Person
//省略setter方法
@end
//Person調(diào)用
main(){
NSMutableArray *books = [@[@"book1"] mutableCopy];
Person *person = [[Person alloc] init];
person.bookArray1 = books;
person.bookArray2 = books;
[books addObject:@"book2"];
NSLog(@"bookArray1:%@",person.bookArray1);
NSLog(@"bookArray2:%@",person.bookArray2);
}
我們看到皂林,使用strong修飾的person.bookArray1輸出是[book1,book2],而使用copy修飾的person.bookArray2輸出是[book1]宠蚂。這下可以看出來區(qū)別了吧式撼。
備注:使用strong童社,則person.bookArray1與可變數(shù)組books指向同一塊內(nèi)存區(qū)域求厕,books內(nèi)容改變,導(dǎo)致person.bookArray1的內(nèi)容改變,因為兩者是同一個東西呀癣;而使用copy美浦,person.bookArray2在賦值之前,將books內(nèi)容復(fù)制项栏,創(chuàng)建一個新的內(nèi)存區(qū)域浦辨,所以兩者不是一回事,books的改變不會導(dǎo)致person.bookArray2的改變沼沈。
當(dāng)源字符串是NSString時流酬,由于字符串是不可變的,所以列另,不管是strong還是copy屬性的對象芽腾,都是指向源對象,copy操作只是做了次淺拷貝页衙。
當(dāng)源字符串是NSMutableString時摊滔,strong屬性只是增加了源字符串的引用計數(shù),而copy屬性則是對源字符串做了次深拷貝店乐,產(chǎn)生一個新的對象艰躺,且copy屬性對象指向這個新的對象。另外需要注意的是眨八,這個copy屬性對象的類型始終是NSString腺兴,而不是NSMutableString,因此其是不可變的廉侧。
這里還有一個性能問題含长,即在源字符串是NSMutableString,strong是單純的增加對象的引用計數(shù)伏穆,而copy操作是執(zhí)行了一次深拷貝拘泞,所以性能上會有所差異。而如果源字符串是NSString時枕扫,則沒有這個問題陪腌。
所以,在聲明NSString屬性時烟瞧,到底是選擇strong還是copy诗鸭,可以根據(jù)實際情況來定。不過参滴,一般我們將對象聲明為NSString時强岸,都不希望它改變,所以大多數(shù)情況下砾赔,我們建議用copy蝌箍,以免因可變字符串的修改導(dǎo)致的一些非預(yù)期問題
說到底青灼,其實就是不同的修飾符,對應(yīng)不同的setter方法妓盲,
strong對應(yīng)的setter方法杂拨,是將_property先release(_property release),然后將參數(shù)retain(property retain)悯衬,最后是_property = property弹沽。
copy對應(yīng)的setter方法,是將_property先release(_property release)筋粗,然后拷貝參數(shù)內(nèi)容(property copy)策橘,創(chuàng)建一塊新的內(nèi)存地址,最后_property = property娜亿。