#修飾詞retain、assign
***retain侈询、assign妻献、copy在@property中的使用實際上是通過控制set方法進行內(nèi)存管理。下面詳細介紹:***
1. retain
例如:
```
@class Dog
@property (nonatomic,retain) Dog *dog;
```
**注:nonatomic與atomic相對應(yīng)蜘犁,涉及線程翰苫,nonatomic相對atomic來說性能高,而聲明屬性時一般認為atomic,故需在此申明nonatmic**
這里使用了retain奏窑,那么set方法中导披,究竟如何體現(xiàn)
```
- (void)setDog:(Dog *)dog
{
if (_dog != dog) { //判斷是否需要重新賦值
[_dog release]; //釋放舊引用,計數(shù)器-1
_dog = [dog retain]; //重新賦值埃唯,計數(shù)器+1
}
}
```
2. assign:
例如:
```
@property (nonatomic,assign) int count;
```
這里使用了assign撩匕,那么在set方法中,究竟如何體現(xiàn)
```
- (void)setCount:(int)count
{
_count = count;
}
```
3. copy:
例如:
```
@property(nonatomic,copy)NSString *str;
```
這里使用了copy墨叛,那么在set方法中
```
- (void)setStr:(NSString *)str
{
if(_str != str) { //判斷是否需要重新賦值
[_str release]; //釋放舊引用止毕,計數(shù)器-1
_str = [str copy]; //重新賦值,使用copy
}
}
```
##總結(jié):
1. retain:先release舊值漠趁,在retain新值扁凛,在上例中_dog與dog最終指向同一塊內(nèi)存區(qū)域。
2. assign:直接賦值闯传,不考慮內(nèi)存管理谨朝。
3. copy:先release舊值,再copy新值甥绿,copy的本質(zhì)為復(fù)制該內(nèi)所存儲的內(nèi)容字币,重新創(chuàng)建一個對象賦給其相同的內(nèi)容,很明顯妹窖,在copy這個過程中也發(fā)生了一次retain纬朝,不過這是個全新的對象。在上例中骄呼,_str與str最終指向了不同的區(qū)域共苛,但其內(nèi)容一樣。
4. 從retain蜓萄、assign隅茎、copy的特點中:
retain一般適用于OC中的對象
assign一般適用于非OC對象,如int等普通類型
copy一般適用于NSString等不可變的對象嫉沽,因為是重新創(chuàng)建了對象辟犀,并且內(nèi)容不變,因此不用擔心后面的操作會對該屬性的值產(chǎn)生影響绸硕。
##實例分析:
假設(shè)str為對象p的屬性
```
@property (nonatomic,copy)NSString *str;
NSMutableString *s = [[NSMutableString alloc] initWithString:@"hello"];
p.str = s; //此時堂竟,str的值為@”hello“
[s appendString:@"world"]; //此時,s的值是”hello world“玻佩,但是str的值依然為”hello“出嘹。
```
但是如果開始時str的申明為:
```
@property(nonatomic,retain)NSString *str;
```
那么,在進行完[s appendString:@"world"]之后咬崔,str的值將變?yōu)椤県ello world“税稼。因為str與s共用一塊內(nèi)存烦秩,內(nèi)容完全相同,而s是可以改變的郎仆,所以s改變后只祠,str也將改變。
copy:建立一個索引計數(shù)為1的對象扰肌,然后釋放就對象 對NSString
對NSString它指出抛寝,在賦值時使用傳入值的一份拷貝∈镄瘢拷貝工作由copy方法執(zhí)行墩剖,此屬性只對那些實行了NSCopying協(xié)議的對象類型有效。
retain:釋放舊的對象夷狰,將舊對象的值賦予輸入對象,再提高輸入對象的索引計數(shù)為1
對其他NSObject和其子類
對參數(shù)進行release舊值郊霎,再retain新值
指定retain會在賦值時喚醒傳入值的retain消息沼头。此屬性只能用于Objective-C對象類型,而不能用于Core Foundation對象书劝。(原因很明顯进倍,retain會增加對象的引用計數(shù),而基本數(shù)據(jù)類型或者Core Foundation對象都沒有引用計數(shù))购对。
***注意:把對象添加到數(shù)組中時猾昆,引用計數(shù)將增加對象的引用計數(shù)次數(shù)+1***
retain的實際語法為:
- (void)setName:(NSString *)newName {
if (name != newName) {
[name release];
name = [newName retain];
}
}
copy與retain:
Copy其實是建立了一個相同的對象,而retain不是:
比如一個NSString對象骡苞,地址為0X1111,內(nèi)容為@”STR“
Copy到另一個NSString之后解幽,地址為0X2222贴见,內(nèi)容相同新的對象retain為1,舊有對象沒有變化
retain到另外一個NSString之后躲株,地址相同(建立一個指針片部,指針拷貝),內(nèi)容當然相同霜定,這個對象的retain值+1
也就是說retain是指針拷貝档悠,copy是內(nèi)容拷貝。
retain的set方法應(yīng)該是淺復(fù)制望浩,copy的set方法應(yīng)該是深復(fù)制了
copy另一個用法:
copy是內(nèi)容的拷貝辖所,對于像NSString的確實這樣
但是,如果是copy的是一個NSArray呢曾雕?
NSArray *array = [NSArray arrayWithObjects:@"hello",@"world",@"baby"];
NSArray *array2 = [array copy];
這個時候奴烙,系統(tǒng)的確是為array2開辟了一塊內(nèi)存空間,但是我們要認識到的是,array2中的每個元素切诀,只是copy了指向array中相對應(yīng)元素的指針揩环。這便是所謂的”淺復(fù)制“。
assign:簡單輔值幅虑,不更改索引計數(shù)
對基礎(chǔ)數(shù)據(jù)類型(例如NSInteger丰滑,CGFloat)和C數(shù)據(jù)類型(int,float倒庵,double褒墨,char等)適用簡單數(shù)據(jù)類型
此標記說明設(shè)置器直接進行賦值,這也是默認值擎宝。在使用垃圾收集的應(yīng)用程序中郁妈,如果你要一個屬性使用assign,且這個類符合NSCopying協(xié)議绍申,你就要明白指出這個標記噩咪,而不是簡單地使用默認值,否則的話极阅,你將得到一個編譯警告胃碾。這再次向編譯器說明你確實需要賦值,即使它是可拷貝的筋搏。
weak和strong屬性只有在你打開ARC時才會被要求使用仆百,這時你是不能使用retain release autorelease操作,ARC會自動為你做好這些操作奔脐,但是你需要在對象屬性上使用weak和strong俄周,其中strong就相當于retain屬性,而weak相當于assign髓迎。
strong關(guān)鍵字與retain相似栈源,引用計數(shù)自動+1,用實例更能說明一切
@property(nonatomic,strong)NSString *string1;
@property(nonatomic,string)NSString *string2;
self.string1 = @"String1";
self.string2 = self.string1;
self.string1 = nil;
NSLog(@"String2 = %@",self.string2);
結(jié)果是:String2 = String1
***由于string2是strong定義的屬性竖般,所以引用計數(shù)+1甚垦,使得它們指向同一地址內(nèi)容為:@”String1“,不可變字符串每次賦值都會重新開辟新地址涣雕。***
接著我們來看weak關(guān)鍵字:
如果這樣聲明兩個屬性:
@property(nonatomic,strong)NSString *string1;
@property(nonatomic,weak)NSString *string2;
self.string1 = @"String1";
self.string2 = self.string1;
self.string1 = nil;
NSLog(@"String2 = %@",self.string2);
結(jié)果是:String2 = null
***分析下艰亮,由于self.string1與self.string2指向同一地址,且string2沒有retain內(nèi)存地址挣郭,而self.string1 = nil釋放了內(nèi)存迄埃,所以string1為nil。聲明為weak的指針兑障,指針指向的地址一旦被釋放侄非,這些指針都將被賦值為nil蕉汪。這樣的好處能有效的防止野指針。在c/c++開發(fā)過程中逞怨,為何大牛都說指針的控件釋放后者疤,都要講指針賦為NULL。在這兒用weak關(guān)鍵字幫我們做了這一步叠赦。***
##copy
特點:
1. 修改源文件的內(nèi)容驹马,不會影響副文本;
2. 修改副文本的內(nèi)容除秀,不會影響源文件糯累;
OC中copy的作用是:利用一個源對象產(chǎn)生一個副本對象
特點:
1. 修改源對象的屬性和行為,不會影響副本對象册踩;
2. 修改副本對象的屬性和行為泳姐,不會影響源對象。
如何使用copy功能
一個對象可以調(diào)用copy或mutableCopy方法來創(chuàng)建一個副本對象暂吉。
1. copy:創(chuàng)建的時不可變副本(NSString仗岸、NSArray、NSDictionary)借笙。
2. mutableCopy:創(chuàng)建的可變副本(NSMutableString、NSMutableArray较锡、NSMutableDictionary)业稼。
使用copy功能的前提:
1. copy:需要遵守NSCopying協(xié)議,實現(xiàn)copyWithZone:方法蚂蕴。
```
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
```
2. mutableCopy:需要遵守NSMutableCopy協(xié)議低散,實現(xiàn)mutableCopyWithZone:方法
```
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
```
###深復(fù)制和淺復(fù)制的區(qū)別:
**深拷貝**
特點:
1. 源對象和副本對象是不同的兩個對象;
2. 源對象引用計數(shù)器不變骡楼,副本對象計數(shù)器為1(因為是新產(chǎn)生的)熔号。
本質(zhì):產(chǎn)生了新對象
**淺拷貝**
特點:
1. 源對象和副本對象是同一對象;
2. 源對象(副本對象)引用計數(shù)+1鸟整,相當于做一次retain操作引镊。
本質(zhì):沒有產(chǎn)生新的對象。
常見賦值如下:![](http://oh6yavwvf.bkt.clouddn.com/00027.png)
***只有源對象和副本對象都不可變時篮条,才是淺復(fù)制弟头,其他都是深復(fù)制。***
```
/**
NSMutableString調(diào)用mutablecopy:深復(fù)制
*/
void mutableStringMutableCopy()
{
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"age is %d",10];
NSMutableString *copyStr = [srcStr mutableCopy];
[copyStr appendString:@"abc"];
NSLog(@"srcStr=%@,copyStr=%@",srcStr,copyStr);
}
/**
NSMutableString調(diào)用copy:深復(fù)制
*/
void mutableStringCopy()
{
NSMutableString *srcStr = [NSMutableString stringWithFormat@"age is %d",10];
NSString *copyStr = [srcStr copy];
[srcStr appendString:@"abc"];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copySt);
}
/**
NSString調(diào)用mutablecopy:深復(fù)制
*/
void stringMutableCopy()
{
NSString *srcStr = [NSString stringWithFormat:@"age is %d",10];
NSMutableString *copyStr = [srcStr mutableCopy];
[copyStr appendString:@"abc"];
NSLog(@"srcStr=%@, copyStr=%@", srcStr, copyStr);
}
/**
NSString調(diào)用copy:淺復(fù)制
*/
void stringCopy()
{
//copy:產(chǎn)生的肯定是不可變副本
//如果是不可變對象調(diào)用copy方法產(chǎn)出不可變副本涉茧,那么不會產(chǎn)生新的對象
NSString *srcStr = [NSString stringWithFormat:@"age is %d",10];
NSString *copyStr = [srcStr copy];
NSLog(@"%p %p",srcStr,copyStr);
}
```
文章屬于摘抄搬磚赴恨!