1. 程式人生 > >IOS學習筆記assign,retain,copy

IOS學習筆記assign,retain,copy

關於object C@property 屬性解釋
就說下@property裡面的屬性的理解 
以下都是個人理解,望大牛指點


這裡只說我認為比較關鍵的三個屬性
assign retain copy 說這個三個區別


assign 就是簡單的賦值 沒有對retain count 發生任何變化


retain 賦值以後 retain count 會加一




copy 把舊的值 複製過來,重新分配一個記憶體空間儲存 retain count = 1;


好了 現在我們來實現下這些屬性的方法:


先來說說assign 屬性
到底做什麼操作:
-(void) setObject:(id)newValue {
value = newValue; ratain count 沒有發生變化。
}


retain


-(void)setMyObject:(id)newValue{
if (_myObject != newValue) { 
[_myObject release]; 
_myObject = [newValue retain]; 

}


copy


-(void)setMyObject:(id)newValue{
if (_myObject != newValue) { 
[_myObject release]; 
_myObject = [newValue copy]; 

}


先來解釋下copy和retain的區別:
retain:就是把指向記憶體的某一個值的地址傳遞給你了。就是說你們共享使用這個記憶體地址。


copy:就是你記憶體裡面的某一個值被copy,然後在記憶體裡面給它重新分配了地址。與以前的那個已經毫無關係了。


下面來解釋下 assing ,retain ,copy 屬性的實現對於retain count的變化。


首先來說assing 就是目標的地址賦給將要賦給的變數,沒有對retain count 產生影響。
比如:


假使 objetcA 是某一個類的例項變數 @property屬性定義了assing 則:


nsstring* objectB = [[NSString alloc]initWithString:@"aaa"];
objectA = objectB ; 
[objectB release]; retain count = 0


對於retain 屬性變數,假使變數也為objectA 。


eg.1
nsstring* objectB = [[NSString alloc]initWithString:@"aaa"];
objectA = objectB ; 
[objectB release];




eg.2
nsstring* objectB = [[NSString alloc]initWithString:@"aaa"];
self.objectA = objectB ; 
[objectB release]; 


看完兩者獲取感覺疑惑,兩者的區別什麼呢。那得首先從後面的self.說起了,這個self.到底後面的變數做了什麼。(哈哈,你盪漾了)後面那個objectA不能理解為變數,應該是 
函式名。兩者重名,這樣系統預設會將objectA生成的方法對應objectB變數。也就是說,當你在前面的加上self.的時候,系統會根據該方法的屬性生成相應的Setter或者Getter方 
法。
就如eg.1中的那樣,當執行objectB release的時候 retain count 已經為0 ,objectA指向的那部分記憶體已經被釋放。如果你繼續向這個塊記憶體傳送訊息,悲劇了。eg.2 執行會 
是什麼樣子呢,首先他會呼叫前面Setter方法。當執行完setter方法後,retain count的值為2,[objectB release ]後retain count 為1 ,就是說在記憶體裡面,沒有被銷燬。


對於屬性是copy來說從表面上看到的只是在setter 方法retain和copy的區別,最主要的區別前文中已經介紹了,就是在新的記憶體的空間裡面分配一部分記憶體並存放相同的值。即, 
retain count 為1.


當出現self.object = nil 會出現什麼狀況呢。

首先也會只去執行setter方法,不管是retain或者是copy ,執行完之後object 指向的是一個空的記憶體空間。

==============================================================================================

==============================================================================================

以下回答了相關的問題

assign: 簡單賦值,不更改索引計數
copy: 建立一個索引計數為1的物件,然後釋放舊物件
retain:釋放舊的物件,將舊物件的值賦予輸入物件,再提高輸入物件的索引計數為1

Copy其實是建立了一個相同的物件,而retain不是:
比如一個NSString物件,地址為0×1111,內容為@”STR”
Copy到另外一個NSString之 後,地址為0×2222,內容相同,新的物件retain為1, 舊有物件沒有變化

retain到另外一個NSString之 後,地址相同(建立一個指標,指標拷貝),內容當然相同,這個物件的retain值+1

也就是說,retain是指標拷貝,copy是內容拷貝。在拷貝之前,都會釋放舊的物件。

* 使用assign: 對基礎資料型別 (NSInteger)和C資料型別(int, float, double, char,等)
* 使用copy: 對NSString
* 使用retain: 對其他NSObject和其子類

1.readonly表示這個屬性是隻讀的,就是隻生成getter方法,不會生成setter方法.
2.readwrite,設定可供訪問級別
3.retain,是說明該屬性在賦值的時候,先release之前的值,然後再賦新值給屬性,引用再加1。
4.nonatomic,非原子性訪問,不加同步,多執行緒併發訪問會提高效能。注意,如果不加此屬性,則預設是兩個訪問方法都為原子型事務訪問。

retain和copy還有assign的區別

1. 假設你用malloc分配了一塊記憶體,並且把它的地址賦值給了指標a,後來你希望指標b也共享這塊記憶體,於是你又把a賦值給(assign)了b。此時a和b指向同一塊記憶體,請問當a不再需要這塊記憶體,能否直接釋放它?答案是否定的,因為a並不知道b是否還在使用這塊記憶體,如果a釋放了,那麼b在使用這塊記憶體的時候會引起程式crash掉。

2. 瞭解到1中assign的問題,那麼如何解決?最簡單的一個方法就是使用引用計數(reference counting),還是上面的那個例子,我們給那塊記憶體設一個引用計數,當記憶體被分配並且賦值給a時,引用計數是1。當把a賦值給b時引用計數增加到2。這時如果a不再使用這塊記憶體,它只需要把引用計數減1,表明自己不再擁有這塊記憶體。b不再使用這塊記憶體時也把引用計數減1。當引用計數變為0的時候,代表該記憶體不再被任何指標所引用,系統可以把它直接釋放掉。

3. 上面兩點其實就是assign和retain的區別,assign就是直接賦值,從而可能引起1中的問題,當資料為int, float等原生型別時,可以使用assign。retain就如2中所述,使用了引用計數,retain引起引用計數加1, release引起引用計數減1,當引用計數為0時,dealloc函式被呼叫,記憶體被回收。
4. copy是在你不希望a和b共享一塊記憶體時會使用到。a和b各自有自己的記憶體。
5. atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多執行緒環境下,原子操作是必要的,否則有可能引起錯誤的結果。加了atomic,setter函式會變成下面這樣:
if (property != newValue) {
[property release];
property = [newValue retain];
}

關於retain,copy,assign的區別問題其實困擾我很久了,因為在程式中不太常用到copy,assign,所以三者的具體差別一直不太明白。
按照我的理解,assign和retain的區別,就是引入了一個計數器retaincount,就可以對一個記憶體的釋放方便很多。copy,就是把原來的記憶體複製一遍,使各自都擁有一個記憶體,這樣釋放的時候也不會出錯。
assign: 簡單賦值,不更改索引計數(Reference Counting)。
copy: 建立一個索引計數為1的物件,然後釋放舊物件
retain:釋放舊的物件,將舊物件的值賦予輸入物件,再提高輸入物件的索引計數為1
使用assign: 對基礎資料型別 (NSInteger,CGFloat)和C資料型別(int, float, double, char, 等等)
使用copy: 對NSString
使用retain: 對其他NSObject和其子類
nonatomic,非原子性訪問,不加同步,多執行緒併發訪問會提高效能。注意,如果不加此屬性,則預設是兩個訪問方法都為原子型事務訪問

@property(nonatomic, retain) UITextField *userName編譯時自動生成的程式碼
- (UITextField *) userName {
return userName;
}

- (void) setUserName:(UITextField *)userName_ {
[userName release];
userName = [userName_ retain];
}


@property(retain) UITextField *userName自動生成的程式碼

- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}

- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[userName release];
userName = [userName_ retain];
}
}