重識(shí)iOS之Property

筆者最近梳理iOS知識(shí)脈絡(luò),計(jì)劃寫(xiě)一個(gè)名為“重識(shí)iOS”的系列,內(nèi)容來(lái)自平時(shí)的學(xué)習(xí)筆記,參考了一些文章和書(shū)籍,融入自己的理解以記錄。歡迎交流指正。本文為第二篇:Property。

property

介紹

  • 簡(jiǎn)介:屬性(property)是Objective-C的一項(xiàng)特性,用于封裝對(duì)象中的數(shù)據(jù)。這一特性可以令編譯器自動(dòng)編寫(xiě)與屬性相關(guān)的存取方法,并且保存為各種實(shí)例變量。
  • 本質(zhì):屬性的本質(zhì)是實(shí)例變量與存取方法的結(jié)合。@property = ivar + getter + setter

特質(zhì)

  • 原子性: atomic / nonatomic
  • 讀寫(xiě)權(quán)限: readwrite / readonly
  • 內(nèi)存管理語(yǔ)義: assign / strong / copy / weak / unsafe_unretained
  • 方法名: getter=<name> / setter=<name>

atomic 與 nonatomic

問(wèn)題:什么是原子性? 說(shuō)明并比較atomic和nonatomic。 atomic是百分之百安全的嗎?

  • 原子性:并發(fā)編程中確保其操作具備整體性,系統(tǒng)其它部分無(wú)法觀察到中間步驟,只能看到操作前后的結(jié)果。
  • atomic:原子性的,編譯器會(huì)通過(guò)鎖定機(jī)制確保 settergetter 的完整性。
  • nonatomic:非原子性的,不保證 settergetter 的完整性。
  • 區(qū)別:由于要保證操作完整,atomic 速度比較慢,線程相對(duì)安全; nonatomic 速度比較快,但是線程不安全。 atomic 也不是絕對(duì)的線程安全,當(dāng)多個(gè)線程同時(shí)調(diào)用 settergetter 時(shí),就會(huì)導(dǎo)致獲取的值不一樣。由于鎖定機(jī)制開(kāi)銷較大,一般iOS開(kāi)發(fā)中會(huì)使用 nonatomic ,而macOS中使用 atomic 通常不會(huì)有性能瓶頸。
  • 拓展:要想線程絕對(duì)安全,就要使用 @synchronized 同步鎖。但是由于同步鎖有等待操作,會(huì)降低代碼效率。為了兼顧線程安全和提升效率,可采用GCD并發(fā)隊(duì)列進(jìn)行優(yōu)化改進(jìn)。getter 使用同步派發(fā),setter 使用異步柵欄。
//同步鎖
- (NSString *)someString {
    @synchronized(self) {
        return _someString;
    }
}

- (void)setSomeString:(NSString *)someString {
    @synchronized(self) {
        _someString = someString;
    }
}

//并發(fā)隊(duì)列
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

- (NSString *)someString {
    __block NSString *localSomeString;
    dispatch_sync(_queue, ^{
        localSomeString = _someString;
    });
    return localSomeString;
}

- (void)setSomeString:(NSString *)someString {
    dispatch_barrier_async(_queue, ^{
    _someString = someString;
    });
}

readwrite 與 readonly

讀寫(xiě)權(quán)限不寫(xiě)時(shí)默認(rèn)為 readwrite 。一般可在 .h 里寫(xiě)成 readonly,只對(duì)外提供讀取,在 .mextension中再設(shè)置為 readwrite 可進(jìn)行寫(xiě)入。

//.h文件
#import <Foundation/Foundation.h>

@interface MyClass : NSObject

@property (nonatomic, readonly, copy) NSString *name;

@end


//.m文件
#import "MyClass.h"

@interface MyClass()

@property (nonatomic, readwrite, copy) NSString *name;

@end

內(nèi)存管理語(yǔ)義

關(guān)鍵詞

  • strong:表示指向并擁有該對(duì)象。其修飾的對(duì)象引用計(jì)數(shù)會(huì) +1 ,該對(duì)象只要引用計(jì)數(shù)不為 0 就不會(huì)銷毀,強(qiáng)行置空可以銷毀它。一般用于修飾對(duì)象類型、字符串和集合類的可變版本。
  • copy:與 strong類似,設(shè)置方法會(huì)拷貝一份副本。一般用于修飾字符串和集合類的不可變版以及block (歷史遺留問(wèn)題)。
  • weak:表示指向但不擁有該對(duì)象。其修飾的對(duì)象引用計(jì)數(shù)不會(huì)增加,屬性所指的對(duì)象銷毀時(shí)屬性值會(huì)清空。ARC環(huán)境下一般用于修飾可能會(huì)引起循環(huán)引用的對(duì)象,delegatexib 控件用 weak 修飾。
  • assign:主要用于修飾基本數(shù)據(jù)類型,如 NSItegerCGFloat 等,這些數(shù)值主要存在于棧中。
  • unsafe_unretained:與weak 類似,但是銷毀時(shí)不自動(dòng)清空,容易形成野指針。

比較 copy 與 strong

  • 相同:用于修飾表示擁有關(guān)系的對(duì)象。
  • 不同:strong 復(fù)制是多個(gè)指針指向同一個(gè)地址,而 copy 的復(fù)制是每次會(huì)在內(nèi)存中復(fù)制一份對(duì)象,指針指向不同的地址。NSString 、NSArrayNSDictionary 等不可變對(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)引用。
  • 不同點(diǎn):weak 引用的對(duì)象被銷毀時(shí), 指針會(huì)被自動(dòng)清空,不再指向銷毀的對(duì)象,不會(huì)產(chǎn)生野指針錯(cuò)誤; unsafe_unretain 引用的對(duì)象被銷毀時(shí), 指針并不會(huì)被自動(dòng)清空, 依然指向銷毀的對(duì)象,很容易產(chǎn)生野指針錯(cuò)誤: EXC_BAD_ACCESS ; assign 修飾基本數(shù)據(jù)類型,內(nèi)存在棧上由系統(tǒng)自動(dòng)回收。

存儲(chǔ)方法名

getter=<name>setter=<name><> 中為方法名,通過(guò)此特質(zhì)來(lái)指定存取方法的名稱。

//.h文件
@interface MyClass : NSObject

@property (nonatomic, assign, getter=isOn) BOOL on;

@end

//.m文件
@implementation MyClass

- (BOOL)isOn {
    return self.on;
}

@end

默認(rèn)設(shè)置

property有默認(rèn)設(shè)置。

  • 基本數(shù)據(jù)類型:atomic, readwrite, assign
  • 對(duì)象類型:atomic, readwrite, strong
  • 注意:考慮到代碼可讀性以及日常代碼修改頻率,規(guī)范的編碼風(fēng)格中關(guān)鍵詞的順序是:原子性、讀寫(xiě)權(quán)限、內(nèi)存管理語(yǔ)義、getter/getter

延伸

我們已經(jīng)知道 @property 會(huì)使編譯器自動(dòng)編寫(xiě)訪問(wèn)這些屬性所需的方法,此過(guò)程在編譯期完成,稱為 自動(dòng)合成 (autosynthesis)。與此相關(guān)的還有兩個(gè)關(guān)鍵詞:@dynamic@synthesize。

  • @dynamic:告訴編譯器不要自動(dòng)創(chuàng)建實(shí)現(xiàn)屬性所用的實(shí)例變量,也不要為其創(chuàng)建存取方法。即使編譯器發(fā)現(xiàn)沒(méi)有定義存取方法也不會(huì)報(bào)錯(cuò),運(yùn)行期會(huì)導(dǎo)致崩潰。
  • @synthesize:在類的實(shí)現(xiàn)文件里可以通過(guò) @synthesize 指定實(shí)例變量的名稱。
  • 注意:在Xcode4.4之前,@property 配合 @synthesize使用,@property 負(fù)責(zé)聲明屬性,@synthesize 負(fù)責(zé)讓編譯器生成 帶下劃線前綴的實(shí)例變量并且自動(dòng)生成 setter、 getter方法。Xcode4.4之后 @property 得到增強(qiáng),直接一并替代了 @synthesize 的工作。

參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1xx消息 這一類型的狀態(tài)碼,代表請(qǐng)求已被接受,需要繼續(xù)處理。這類響應(yīng)是臨時(shí)響應(yīng),只包含狀態(tài)行和某些可選的響應(yīng)頭信...
    松n_n鼠閱讀 292評(píng)論 0 1
  • 一個(gè)不重視教育的民族,是一個(gè)沒(méi)有希望的民族,一個(gè)不重視教育的國(guó)家,是一個(gè)沒(méi)有前途的國(guó)家,一個(gè)不重視教育的家庭,...
    郝長(zhǎng)笑閱讀 645評(píng)論 0 0
  • 喜歡淡淡的味道 香噴噴的感覺(jué) 甜甜的心情
    水筆仔o12530閱讀 252評(píng)論 0 0

友情鏈接更多精彩內(nèi)容