理解屬性property

可以用@property語(yǔ)法來(lái)定義對(duì)象中所封裝的數(shù)據(jù)
通過(guò)"特質(zhì)(arrribute)"來(lái)指定存儲(chǔ)數(shù)據(jù)所需的正確語(yǔ)義
在設(shè)置屬性所對(duì)應(yīng)的實(shí)例變量時(shí)胆剧,一定要遵從該屬性所聲明的語(yǔ)義
在開(kāi)發(fā)iOS程序時(shí)應(yīng)該使用nonatomic屬性挠他,因?yàn)閍tomic會(huì)嚴(yán)重影響性能
在對(duì)象內(nèi)部盡量直接訪問(wèn)實(shí)例變量

"屬性(property)"是Objective-C的一項(xiàng)特性礼搁,用于封裝對(duì)象中的數(shù)據(jù)。Objective-C對(duì)象通常會(huì)把其所需要的重要數(shù)據(jù)保存為各種實(shí)例變量濒旦。實(shí)例變量一般通過(guò)存取(getter和setter)方法來(lái)訪問(wèn)

在描述個(gè)人信息時(shí)娜庇,通過(guò)存放人名偎漫,生日爷恳,地址等內(nèi)容,可以在類接口的public區(qū)段聲明一些實(shí)例變量

@interface:NSObject{
@public
    NSString *_firstName;
    NSString *_lastName;
@private
    NSString *_someIntenalData;
}
@end

這種編寫(xiě)風(fēng)格類似于C++和Java象踊。但是Objective-C幾乎不會(huì)這樣做温亲,因?yàn)檫@樣的寫(xiě)法,對(duì)象布局在編譯器就已經(jīng)確定杯矩,當(dāng)要訪問(wèn)一個(gè)屬性的時(shí)候栈虚,使用的是硬編碼之后的偏移量(offset),表示該變量存放在對(duì)象起始地址有多遠(yuǎn)。如果要在_fisrtName前面再加上一個(gè)變量史隆,那么之前所指的偏移量都指向了錯(cuò)誤的地址魂务,修改之后必須重新編譯。

例如泌射,某個(gè)代碼庫(kù)中的代碼使用了一份舊的類定義粘姜。如果與之相連接的代碼使用了新的定義,那么運(yùn)行的時(shí)候就會(huì)出現(xiàn)不兼容的現(xiàn)象熔酷。各種語(yǔ)言均有相應(yīng)的解決方法.Objective-C的做法是把存儲(chǔ)偏移量所用的"特殊變量"交給類對(duì)象來(lái)保存孤紧。偏移量會(huì)在運(yùn)行時(shí)查找,如果類定義變了拒秘,那么存儲(chǔ)的偏移量也就變了号显,這樣可以保證何時(shí)訪問(wèn)實(shí)例變量,總能找到正確的偏移量躺酒。甚至可以在運(yùn)行期向類中新增實(shí)例變量押蚤,這就是穩(wěn)固的"應(yīng)用程序二進(jìn)制接口(Application Binary Interface,ABI)"
正是因?yàn)檫@些特性,使得我們可以在"類擴(kuò)展(class-continuation)"或?qū)崿F(xiàn)文件中定義實(shí)例變量羹应。所以說(shuō)揽碘,不一定要在接口中把全部實(shí)例變量都聲明好,可以將某些變量從接口的public區(qū)段移走,以便保護(hù)與類實(shí)現(xiàn)有關(guān)的內(nèi)部信息钾菊。
盡量不要對(duì)象外部直接訪問(wèn)實(shí)例變量,而應(yīng)該通過(guò)存取方法來(lái)做(因?yàn)檫\(yùn)行時(shí)機(jī)制)偎肃,可以使用@property語(yǔ)法來(lái)編寫(xiě)實(shí)例變量煞烫,@property會(huì)自動(dòng)生成對(duì)應(yīng)的存取方法。
例如:

@interface Person:NSObject
@property  NSString *firstName;
@end

對(duì)于類的使用者來(lái)說(shuō)累颂,相當(dāng)于

//Person.h
@interface Person:NSObject
- (NSString *)firstName;
- (void)setFirstName:(NSString*)firstName;
@end
//Person.m
@implement Person
@synthesize _firstName;
@end

如果讀寫(xiě)用@property定義的屬性滞详,可以使用點(diǎn)語(yǔ)法,編譯器會(huì)自動(dòng)將點(diǎn)語(yǔ)法轉(zhuǎn)換為對(duì)應(yīng)的存取方法;

Person *person = [[Person alloc]init];
NSString * temp = person.firstName;
person.firstName = @"Test";

編譯后會(huì)變成

Person *person = [[Person alloc]init];
NSString * temp = [person firstName];
[person setFirstName:@"Test"];

屬性特質(zhì)

使用屬性時(shí)還有一個(gè)問(wèn)題需要注意紊馏,就是其各種特質(zhì)(arrribute)設(shè)定也會(huì)影響編譯器所產(chǎn)生的存取方式料饥,屬性可以擁有的特質(zhì)分為以下四類

原子性

在默認(rèn)情況下,由編譯產(chǎn)生的合成方式會(huì)通過(guò)鎖定機(jī)制來(lái)確保其原子性(atomic)朱监,如果屬性具備nonatomic特質(zhì)岸啡,則不使用同步鎖。
如果開(kāi)發(fā)iOS應(yīng)用赫编,你會(huì)發(fā)現(xiàn)巡蘸,其中所有的屬性都聲明為nonatomic。這樣做是因?yàn)樵陂_(kāi)發(fā)iOS中使用同步鎖的開(kāi)銷較大擂送,這會(huì)帶來(lái)性能問(wèn)題悦荒,一般情況下并不要求屬性必須是"原子的",因?yàn)檫@并不能保證線程安全嘹吨,如果要實(shí)現(xiàn)線程安全的操作搬味,必須使用更深層次的鎖定機(jī)制才可以。也就是說(shuō)蟀拷,一個(gè)線程在連續(xù)多次讀取某屬性的過(guò)程中碰纬,有別的線程在同時(shí)改寫(xiě)該值,那么即使將屬性聲明為atomic问芬,也還是會(huì)讀到不同的屬性值嘀趟。因此在開(kāi)發(fā)iOS程序時(shí),一般都會(huì)使用nonatomic屬性愈诚。但是在開(kāi)發(fā)macOS程序的時(shí)候她按,使用atomic一般不會(huì)有性能瓶頸。

讀/寫(xiě)權(quán)限

  • readwrite(讀寫(xiě))特質(zhì)的屬性擁有獲取(getter)方法和設(shè)置(setter)方法炕柔,這是默認(rèn)的讀寫(xiě)屬性酌泰,如果不指明,默認(rèn)就是readwrite
  • readonly只讀匕累,只有讀取方法陵刹,沒(méi)有對(duì)外的設(shè)置方法

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

屬性用于封裝數(shù)據(jù),而數(shù)據(jù)則要有"具體的所有權(quán)語(yǔ)義"

  • assign 設(shè)置方法只會(huì)針對(duì)"純量類型"(scalar type,例如CGFloat或者NSInteger等)進(jìn)行簡(jiǎn)單的賦值操作欢嘿,Objective-C的基本類型和所有在棧上存儲(chǔ)的變量使用這個(gè)特質(zhì)
  • strong 表示擁有關(guān)系衰琐,強(qiáng)引用等同于retain
  • weak 表示弱引用也糊,對(duì)象不擁有該屬性,對(duì)象遭到摧毀的時(shí)候羡宙,屬性值也會(huì)設(shè)為nil
  • unsafe_unretained 該特質(zhì)語(yǔ)義和assign類似狸剃,但是它適用于"對(duì)象類型",該特質(zhì)表示一種非擁有關(guān)系,與weak的區(qū)別在于狗热,對(duì)象摧毀的時(shí)候钞馁,屬性值不會(huì)被設(shè)置為nil(unsafe)
  • copy 此特質(zhì)表達(dá)所屬關(guān)系和strong類似,但是是保留一份拷貝的值匿刮,NSString一般要使用該特質(zhì)

方法名

@property默認(rèn)為屬性生成getter和setter方法名,如果需要自行制定getter和setter方法的方法名僧凰,可以使用該特質(zhì)

  • getter = < name >:指定"獲取方法"的方法名,一般屬性是Boolean型熟丸,而你想為獲取方法加上"is"前綴训措,那么可以使用該特質(zhì)
@property (nonatomic,getter = isOn) BOOL on;
  • **setter = < name > **:指定設(shè)置方法使用的方法名,不常用

屬性在對(duì)象內(nèi)部的訪問(wèn)

使用@property生成的變量光羞,在實(shí)現(xiàn)文件中會(huì)自動(dòng)生成一個(gè)以"_"開(kāi)頭的同名變量(見(jiàn)上述)隙弛。那么,在對(duì)象內(nèi)部是直接訪問(wèn)還是使用屬性訪問(wèn)好呢狞山。
例如

@interface Person:NSObject
@property (nonatomic,copy) NSString *firstName;
@property (nonatomic,copy) NSString *lastName;
- (NSString *) fullName;
@end

fullName方法在內(nèi)部有兩種實(shí)現(xiàn)方式

//方法一:使用屬性訪問(wèn)
- (NSString *)fullName
{
    return [NSString stringWithFormat:@"%@ %@",self.firstName,self.lastName];  
}

//方法二:使用直接訪問(wèn)
- (NSString *)fullName
{
    return [NSString stringWithFormat:@"%@ %@",_firstName,_lastName];  
}

這兩個(gè)寫(xiě)法的區(qū)別在于

  • 直接訪問(wèn)不經(jīng)過(guò)Objective-C的"方法派發(fā)"全闷,所以速度更快一些
  • 直接訪問(wèn)實(shí)例變量,不會(huì)調(diào)用其"設(shè)置方法"萍启,這就繞過(guò)了相關(guān)屬性所定義的"內(nèi)存管理語(yǔ)義",比方說(shuō)总珠,如果在ARC下直接訪問(wèn)一個(gè)聲明為copy的屬性,那么并不會(huì)拷貝該屬性勘纯,只會(huì)保留新值釋放舊值局服。
  • 如果直接訪問(wèn)實(shí)例變量,不會(huì)觸發(fā)KVO
  • 通過(guò)屬性來(lái)訪問(wèn)有助有排查與之相關(guān)的錯(cuò)誤驳遵,因?yàn)榭梢越ogetter和setter設(shè)置斷點(diǎn)

可以看出淫奔,屬性訪問(wèn)和直接訪問(wèn)各有優(yōu)勢(shì),一種折中的方式是:

  • 寫(xiě)入實(shí)例變量的時(shí)候,使用屬性訪問(wèn)
  • 讀取實(shí)例變量的時(shí)候堤结,直接訪問(wèn)唆迁。

這樣既能提高讀取操作的速度,又能控制對(duì)屬性的寫(xiě)入操作竞穷。

需要注意的是唐责,

  • 在初始化中應(yīng)該如何設(shè)置屬性值,這種情況下瘾带,一般使用直接訪問(wèn)實(shí)例變量來(lái)讀寫(xiě)變量鼠哥,因?yàn)樽宇惪赡軙?huì)overwrite屬性的設(shè)置方法。
  • 懶加載(lazy initialzation), 在懶加載的情況下朴恳,應(yīng)該使用"獲取方法"來(lái)訪問(wèn)屬性抄罕。否則,實(shí)例變量就永遠(yuǎn)不會(huì)被初始化于颖。

懶加載:對(duì)于有些變量呆贿,如果使用頻率較低,而且創(chuàng)建該變量的成本較高恍飘,那么應(yīng)該使用懶加載榨崩,在內(nèi)部其他地方使用懶加載的變量的時(shí)候谴垫,不能使用直接訪問(wèn)的方式來(lái)訪問(wèn)章母,而是要通過(guò)屬性(獲取方法getter)來(lái)訪問(wèn)(注意,只有g(shù)etter內(nèi)部可以直接訪問(wèn)變量)翩剪,例如乳怎,如果Person對(duì)象有個(gè)brain屬性,懶加載的getter可以這樣寫(xiě)

- (Brain *)brain
{
    if(!_brain){
        _brain = [Brain new];
    }   
    return _brain;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末前弯,一起剝皮案震驚了整個(gè)濱河市蚪缀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恕出,老刑警劉巖询枚,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異浙巫,居然都是意外死亡金蜀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)的畴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)渊抄,“玉大人,你說(shuō)我怎么就攤上這事丧裁』よ耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵煎娇,是天一觀的道長(zhǎng)二庵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)缓呛,這世上最難降的妖魔是什么眨猎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮强经,結(jié)果婚禮上睡陪,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好兰迫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布信殊。 她就那樣靜靜地躺著,像睡著了一般汁果。 火紅的嫁衣襯著肌膚如雪涡拘。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天据德,我揣著相機(jī)與錄音鳄乏,去河邊找鬼。 笑死棘利,一個(gè)胖子當(dāng)著我的面吹牛橱野,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播善玫,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼水援,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了茅郎?” 一聲冷哼從身側(cè)響起蜗元,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎系冗,沒(méi)想到半個(gè)月后奕扣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掌敬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年惯豆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涝开。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡循帐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出舀武,到底是詐尸還是另有隱情拄养,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布银舱,位于F島的核電站瘪匿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏寻馏。R本人自食惡果不足惜棋弥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诚欠。 院中可真熱鬧顽染,春花似錦漾岳、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至唧垦,卻和暖如春捅儒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背振亮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工巧还, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坊秸。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓麸祷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親妇斤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子摇锋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容