iOS開(kāi)發(fā)—屬性關(guān)鍵字詳解
@Property
什么是屬性?
- 屬性
(property)是Objective-C的一項(xiàng)特性,用于封裝對(duì)象中的數(shù)據(jù)。這一特性可以令編譯器自動(dòng)編寫(xiě)與屬性相關(guān)的存取方法,并且保存為各種實(shí)例變量。 - 屬性的本質(zhì)是實(shí)例變量與存取方法的結(jié)合。
@property = ivar + getter + setter- 實(shí)現(xiàn)流程:
- 每次增加一個(gè)屬性,系統(tǒng)都會(huì)在
ivar_list中添加一個(gè)成員變量的描述,在method_list中增加setter與getter方法的描述,在prop_list中增加一個(gè)屬性的描述,計(jì)算該屬性在對(duì)象中的偏移量,然后給出setter與getter方法對(duì)應(yīng)的實(shí)現(xiàn)。在setter方法中從偏移量的位置開(kāi)始賦值,在getter方法中從偏移量開(kāi)始取值,為了能夠讀取正確字節(jié)數(shù),系統(tǒng)對(duì)象偏移量的指針類(lèi)型進(jìn)行了類(lèi)型強(qiáng)轉(zhuǎn)。
Property的默認(rèn)設(shè)置
- 基本數(shù)據(jù)類(lèi)型:
atomic,readwrite,assign - 對(duì)象類(lèi)型:
atomic,readwrite,strong
??:注意:考慮到代碼可讀性以及日常代碼修改頻率,規(guī)范的編碼風(fēng)格中關(guān)鍵詞的順序是:原子性、讀寫(xiě)權(quán)限、內(nèi)存管理語(yǔ)義、getter/getter。
關(guān)鍵字
| 關(guān)鍵字 | 解釋 |
|---|---|
| atomic | 原子性訪問(wèn) |
| nonatomic | 非原子性訪問(wèn),多線程并發(fā)訪問(wèn)會(huì)提高性能 |
| readwrite | 此標(biāo)記說(shuō)明屬性會(huì)被當(dāng)成讀寫(xiě)的,這也是默認(rèn)屬性 |
| readonly | 此標(biāo)記說(shuō)明屬性只可以讀,也就是不能設(shè)置,可以獲取 |
| strong | 打開(kāi)ARC時(shí)才會(huì)使用,相當(dāng)于retain |
| weak | 打開(kāi)ARC時(shí)才會(huì)使用,相當(dāng)于assign,可以把對(duì)應(yīng)的指針變量置為nil |
| assign | 不會(huì)使引用計(jì)數(shù)加1,也就是直接賦值 |
| unsafe_unretain | 與weak類(lèi)似,但是銷(xiāo)毀時(shí)不自動(dòng)清空,容易形成野指針 |
| copy | 與strong類(lèi)似,設(shè)置方法會(huì)拷貝一份副本。一般用于修飾字符串和集合類(lèi)的不可變版, block用copy修飾 |
詳解copy
-
copy語(yǔ)法的作用:- 產(chǎn)生副本
-
copy返回的是不可變的副本 -
mutableCopy返回的是可變的副本
-
- 修改了副本并不會(huì)影響源對(duì)象,修改了源對(duì)象,并不會(huì)影響副本。
- 產(chǎn)生副本
-
copy使用場(chǎng)景:-
NSString、NSArray、NSictionary等等經(jīng)常使用copy關(guān)鍵字,是因?yàn)樗麄冇袑?duì)應(yīng)的可變類(lèi)型:NSMutableString、NSMutableArray、NSMutableDictionary.為確保對(duì)象中的屬性值不會(huì)無(wú)意間變動(dòng),應(yīng)該在設(shè)置新屬性值時(shí)拷貝一份,保護(hù)其封裝性 -
block,也經(jīng)常使用copy使用
copy是從MRC遺留下來(lái)的“傳統(tǒng)”,在MRC中,方法內(nèi)部的block是在棧區(qū)的,使用copy可以把它放到堆區(qū).在
ARC中寫(xiě)不寫(xiě)都行:對(duì)于block使用copy還是strong效果是一樣的,但是建議寫(xiě)上copy,因?yàn)檫@樣顯示告知調(diào)用者“編譯器會(huì)自動(dòng)對(duì) block 進(jìn)行了copy操作.
-
-
為什么用
@property聲明的NSString(或NSArray,NSDictionary)經(jīng)常使用copy關(guān)鍵字,為什么?如果改用strong關(guān)鍵字,可能造成什么問(wèn)題?- 因?yàn)楦割?lèi)指針可以指向子類(lèi)對(duì)象,使用
copy的目的是為了讓本對(duì)象的屬性不受外界影響,使用copy無(wú)論給我傳入是一個(gè)可變對(duì)象還是不可對(duì)象,我本身持有的就是一個(gè)不可變的副本. 如果我們使用是strong,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.
- 因?yàn)楦割?lèi)指針可以指向子類(lèi)對(duì)象,使用
-
如何讓自定義類(lèi)可以用
copy修飾符?如何重寫(xiě)帶copy關(guān)鍵字的setter?- 若想令自己所寫(xiě)的對(duì)象具有拷貝功能,則需實(shí)現(xiàn)
NSCopying協(xié)議。如果自定義的對(duì)象分為可變版本與不可變版本,那么就要同時(shí)實(shí)現(xiàn)NSCopyiog與NSMutableCopying協(xié)議,不過(guò)一般沒(méi)什么必要,實(shí)現(xiàn)NSCopying協(xié)議就夠了
- (id)copyWithZone:(NSZone *)zone { NSObject *copyObj = [[NSObject allocWithZone:zone] init]; copyObj.name = self.name; return copyObj; } - (void)setName;(Mitchell*)name { _name = [name copy]; } - 若想令自己所寫(xiě)的對(duì)象具有拷貝功能,則需實(shí)現(xiàn)
atomic與nonatomic
- 什么是原子性?
- 并發(fā)編程中確保其操作具備整體性,系統(tǒng)其它部分無(wú)法觀察到中間步驟,只能看到操作前后的結(jié)果
- atomic:原子性的,編譯器會(huì)通過(guò)鎖定機(jī)制確保
setter和getter的完整性。 - nonatomic:非原子性的,不保證
setter和getter的完整性。 - 區(qū)別:由于要保證操作完整,
atomic速度比較慢,線程相對(duì)安全;nonatomic速度比較快,但是線程不安全。atomic也不是絕對(duì)的線程安全,當(dāng)多個(gè)線程同時(shí)調(diào)用setter和getter時(shí),就會(huì)導(dǎo)致獲取的值不一樣。由于鎖定機(jī)制開(kāi)銷(xiāo)較大,一般iOS開(kāi)發(fā)中會(huì)使用nonatomic,而macOS中使用atomic通常不會(huì)有性能瓶頸。 - 如果對(duì)這塊不太了解,你可以看一下這篇文章atomic到底不安全在哪?
readwrite與readonly
- 讀寫(xiě)權(quán)限不寫(xiě)時(shí)默認(rèn)為 readwrite 。一般可在 .h 里寫(xiě)成readonly,只對(duì)外提供讀取,在 .m 的Extension中再設(shè)置為 readwrite 可進(jìn)行寫(xiě)入。
//.h文件
@interface MyClass : NSObject
@property (nonatomic, readonly, copy) NSString *name;
@end
//.m文件
@interface MyClass()
@property (nonatomic, readwrite, copy) NSString *name;
@end
比較strong與copy
- 相同之處:是用于修飾表示擁有關(guān)系的對(duì)象。
- 不同之處:
strong復(fù)制是多個(gè)指針指向同一個(gè)地址,而copy的復(fù)制是每次會(huì)在內(nèi)存中復(fù)制一份對(duì)象,指針指向不同的地址。-
NSString、NSArray、NSDictionary等不可變對(duì)象用copy修飾,因?yàn)橛锌赡軅魅胍粋€(gè)可變的版本,此時(shí)能保證屬性值不會(huì)受外界影響。
-
- 注意??:若用
strong修飾NSArray,當(dāng)數(shù)組接收一個(gè)可變數(shù)組,可變數(shù)組若發(fā)生變化,被修飾的屬性數(shù)組也會(huì)發(fā)生變化,也就是說(shuō)屬性值容易被篡改;若用copy修飾NSMutableArray,當(dāng)試圖修改屬性數(shù)組里的值時(shí),程序會(huì)崩潰,因?yàn)閿?shù)組被復(fù)制成了一個(gè)不可變的版本。
比較assign、weak、unsafe_unretain
- 相同之處:都不是強(qiáng)引用
- 不同之處:
weak引用的 OC 對(duì)象被銷(xiāo)毀時(shí), 指針會(huì)被自動(dòng)清空,不再指向銷(xiāo)毀的對(duì)象,不會(huì)產(chǎn)生野指針錯(cuò)誤;unsafe_unretain引用的 OC 對(duì)象被銷(xiāo)毀時(shí), 指針并不會(huì)被自動(dòng)清空, 依然指向銷(xiāo)毀的對(duì)象,很容易產(chǎn)生野指針錯(cuò)誤:EXC_BAD_ACCESS;assign修飾基本數(shù)據(jù)類(lèi)型,內(nèi)存在棧上由系統(tǒng)自動(dòng)回收。
@synthesize 和 @dynamic
@property有兩個(gè)對(duì)應(yīng)的詞,一個(gè)是@synthesize,一個(gè)是@dynamic。
如果@synthesize和@dynamic都沒(méi)寫(xiě),那么默認(rèn)的就是
@syntheszie var = _var;@synthesize的語(yǔ)義是如果你沒(méi)有手動(dòng)實(shí)現(xiàn) setter 方法和 getter 方法,那么編譯器會(huì)自動(dòng)為你加上這兩個(gè)方法。@dynamic告訴編譯器:屬性的setter與getter方法由用戶自己實(shí)現(xiàn),不自動(dòng)生成。(當(dāng)然對(duì)于readonly的屬性只需提供getter即可)
假如一個(gè)屬性被聲明為@dynamic var;然后你沒(méi)有提供@setter方法和@getter方法,編譯的時(shí)候沒(méi)問(wèn)題,但是當(dāng)程序運(yùn)行到instance.var = someVar,由于缺setter方法會(huì)導(dǎo)致程序崩潰;
或者當(dāng)運(yùn)行到someVar = instance.var時(shí),由于缺getter方法同樣會(huì)導(dǎo)致崩潰。