#修飾詞retain、assign
***retain、assign、copy在@property中的使用實(shí)際上是通過控制set方法進(jìn)行內(nèi)存管理。下面詳細(xì)介紹:***
1. retain
例如:
```
@class Dog
@property (nonatomic,retain) Dog *dog;
```
**注:nonatomic與atomic相對應(yīng),涉及線程,nonatomic相對atomic來說性能高,而聲明屬性時一般認(rèn)為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的特點(diǎn)中:
retain一般適用于OC中的對象
assign一般適用于非OC對象,如int等普通類型
copy一般適用于NSString等不可變的對象,因?yàn)槭侵匦聞?chuàng)建了對象,并且內(nèi)容不變,因此不用擔(dān)心后面的操作會對該屬性的值產(chǎn)生影響。
##實(shí)例分析:
假設(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;
```
那么,在進(jìn)行完[s appendString:@"world"]之后,str的值將變?yōu)椤県ello world“。因?yàn)閟tr與s共用一塊內(nèi)存,內(nèi)容完全相同,而s是可以改變的,所以s改變后,str也將改變。
copy:建立一個索引計數(shù)為1的對象,然后釋放就對象 對NSString
對NSString它指出,在賦值時使用傳入值的一份拷貝??截惞ぷ饔蒫opy方法執(zhí)行,此屬性只對那些實(shí)行了NSCopying協(xié)議的對象類型有效。
retain:釋放舊的對象,將舊對象的值賦予輸入對象,再提高輸入對象的索引計數(shù)為1
對其他NSObject和其子類
對參數(shù)進(jìn)行release舊值,再retain新值
指定retain會在賦值時喚醒傳入值的retain消息。此屬性只能用于Objective-C對象類型,而不能用于Core Foundation對象。(原因很明顯,retain會增加對象的引用計數(shù),而基本數(shù)據(jù)類型或者Core Foundation對象都沒有引用計數(shù))。
***注意:把對象添加到數(shù)組中時,引用計數(shù)將增加對象的引用計數(shù)次數(shù)+1***
retain的實(shí)際語法為:
- (void)setName:(NSString *)newName {
if (name != newName) {
[name release];
name = [newName retain];
}
}
copy與retain:
Copy其實(shí)是建立了一個相同的對象,而retain不是:
比如一個NSString對象,地址為0X1111,內(nèi)容為@”STR“
Copy到另一個NSString之后,地址為0X2222,內(nèi)容相同新的對象retain為1,舊有對象沒有變化
retain到另外一個NSString之后,地址相同(建立一個指針,指針拷貝),內(nèi)容當(dāng)然相同,這個對象的retain值+1
也就是說retain是指針拷貝,copy是內(nèi)容拷貝。
retain的set方法應(yīng)該是淺復(fù)制,copy的set方法應(yīng)該是深復(fù)制了
copy另一個用法:
copy是內(nèi)容的拷貝,對于像NSString的確實(shí)這樣
但是,如果是copy的是一個NSArray呢?
NSArray *array = [NSArray arrayWithObjects:@"hello",@"world",@"baby"];
NSArray *array2 = [array copy];
這個時候,系統(tǒng)的確是為array2開辟了一塊內(nèi)存空間,但是我們要認(rèn)識到的是,array2中的每個元素,只是copy了指向array中相對應(yīng)元素的指針。這便是所謂的”淺復(fù)制“。
assign:簡單輔值,不更改索引計數(shù)
對基礎(chǔ)數(shù)據(jù)類型(例如NSInteger,CGFloat)和C數(shù)據(jù)類型(int,float,double,char等)適用簡單數(shù)據(jù)類型
此標(biāo)記說明設(shè)置器直接進(jìn)行賦值,這也是默認(rèn)值。在使用垃圾收集的應(yīng)用程序中,如果你要一個屬性使用assign,且這個類符合NSCopying協(xié)議,你就要明白指出這個標(biāo)記,而不是簡單地使用默認(rèn)值,否則的話,你將得到一個編譯警告。這再次向編譯器說明你確實(shí)需要賦值,即使它是可拷貝的。
weak和strong屬性只有在你打開ARC時才會被要求使用,這時你是不能使用retain release autorelease操作,ARC會自動為你做好這些操作,但是你需要在對象屬性上使用weak和strong,其中strong就相當(dāng)于retain屬性,而weak相當(dāng)于assign。
strong關(guān)鍵字與retain相似,引用計數(shù)自動+1,用實(shí)例更能說明一切
@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
特點(diǎn):
1. 修改源文件的內(nèi)容,不會影響副文本;
2. 修改副文本的內(nèi)容,不會影響源文件;
OC中copy的作用是:利用一個源對象產(chǎn)生一個副本對象
特點(diǎ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é)議,實(shí)現(xiàn)copyWithZone:方法。
```
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
```
2. mutableCopy:需要遵守NSMutableCopy協(xié)議,實(shí)現(xiàn)mutableCopyWithZone:方法
```
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
```
###深復(fù)制和淺復(fù)制的區(qū)別:
**深拷貝**
特點(diǎn):
1. 源對象和副本對象是不同的兩個對象;
2. 源對象引用計數(shù)器不變,副本對象計數(shù)器為1(因?yàn)槭切庐a(chǎn)生的)。
本質(zhì):產(chǎn)生了新對象
**淺拷貝**
特點(diǎn):
1. 源對象和副本對象是同一對象;
2. 源對象(副本對象)引用計數(shù)+1,相當(dāng)于做一次retain操作。
本質(zhì):沒有產(chǎn)生新的對象。
常見賦值如下:
***只有源對象和副本對象都不可變時,才是淺復(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);
}
```
文章屬于摘抄搬磚!