iOS開發中@property的屬性weak nonatomic strong readonly等介紹
//property:屬性;
//synthesize:綜合;
@property與@synthesize是成對出對出現的,可以自動生成某個類成員變量的存取方法。
在Xcode4.5以及以后的版本,@synthesize可以省略。
//atomic:原子的
//nonatomic:無原子的
1.atomic與nonatomic
atomic:默認是由該屬性的,這個屬性是為了保證程序在多線程情況,編譯器會自動生成一些互斥加鎖代碼,避免該變量的讀寫不同步問題。
nonatomic:如果該對象無需考慮多線程的情況,請加入這個屬性,這樣會讓編譯器少生成一些互斥加鎖代碼,可以提高效率。
2.readwrite與readonly
readwrite:這個屬性是默認的情況,會自動為你生成存取器。
readonly:只生成getter不會有setter方法。
readwrite、readonly這兩個屬性的真正價值,不是提供供成員變量訪問接口,而是控制成員變量的訪問權限。
3.strong與weak(弱引用)
strong:強引用,也是我們通常說的引用,其存亡直接決定了所指向對象的存亡。如果不存在指向一個對象引用,
並且此對象不在顯示在列表中,則此對象會被從內存中釋放。
weak:弱引用,不決定對象的存亡。即使一個對象被持有無數個弱引用,只要沒有強引用指向它,那么還是會被清除。
strong與retain功能相似;weak與assign相似,只是當對象消失后weak會自動把指針變為nil.
//assign:分配
//retain:保留
4.assign、copy、retain
assign:默認類型,setter方法直接賦值,不進行任何retain操作,不改變引用計數。一般用來處理基本數據類型。
retain:釋放舊的對象(release),將舊對象的值賦給新對象,再令新對象引用技術為1。我理解為指針的拷貝,拷貝一份原來
的指針,釋放原來指針指向的對象內容,再令指針指向新的對象內容。
copy:與retain處理流程一樣,先對舊值release,再copy出新的對象,retainCount為1。為了減少對上下文的依賴而引入的機制。
我理解為內容的拷貝,向內存申請一塊空間,把原來的對象內容賦給它,令其引用計數為1。對copy屬性要特別注意:被定義有
copy屬性的對象必須要符合NSCopying協議,必須實現-(id)copyWithZone:(NSZone*)zone方法。
也可以直接使用:
使用assign:對基礎數據類型(NSInteger、CGFloat)和C數據類型(int、float、double、char等等)。
使用copy:對NSString
使用retain:對其他NSObject和其子類
5.getter setter
getter:是用來指定get方法的方法名
setter:是用來指定set訪問的方法名
在@property的屬性中,如果這個屬性是一個BOOL值,通常我們可以用getter來定義一個自己喜歡的名字,
例如:
@property(nonatomic,assign,getter=isValue) boolean value; @property(nonatomic,assign,setter=setIsValue) boolean value;
一、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..atomic和nonatomic用來決定編譯器的生成getter和setter是否為原子操作。在多線程環境下,原子操作是必要的,否則有可能引起錯誤結果。
加了atomic,setter函數會變成下面這樣:
if(property != newValue){ [property release]; property=[newValue retain]; }
二、深入理解一下(包括antorelease)
1.retain之后count加1。alloc之后count就是1,release就會調用dealloc銷毀這個對象。
如果retain,需要release兩次。通常在method中把參數賦給成員變量時需要retain.
例如:
classA有setName這個方法: -(void)setName(ClassName *) inputName { name=inputName; [name retain];//此處retain,等同於[inputName retain],count等於2 }
調用時:
ClassName *myName=[[ClassName alloc] init]; [[classA setName:myName]; //retain count == 2 [myName release]; //retain count==1,在ClassA的dealloc中release name才能真正釋放內存。]
2、autorelease更加tricky,而且很容易被它的名字迷惑。我在這里要強調一下:autorelease不是garbage collection,
完全不同於Java或者.Net中的GC。
autorelease和作用域沒有任何關系!
autorelease 原理:
a.先建立一個autorelease pool
b.對象從這個autorelease pool里面生成。
c.對象生成 之后調用autorelease函數,這個函數的作用僅僅是在autorelease pool中做個標記,讓pool記得將來release一下這個對象。
d.程序結束時,pool本身也需要rerlease, 此時pool會把每一個標記為autorelease的對象release一次。
如果某個對象此時retain count大於1,這個對象還是沒有被銷毀。
上面這個例子應該這樣寫:
ClassName *myName = [[[ClassName alloc] init] autorelease];//標記為autorelease [classA setName:myName]; //retain count == 2 [myName release]; //retain count==1,注意,在ClassA的dealloc中不能release name,否則release pool時會release這個retain count為0的對象,這是不對的。
記住一點:如果這個對象是你alloc或者new出來的,你就需要調用release。
如果使用autorelease,那么僅在發生過retain的時候release一次(讓retain count始終為1)。
3 xcode 中的新標記 strong weak
strong 用來修飾強引用的屬性;對應以前retain
weak 用來修飾弱引用的屬性;對應以前的assign。