iOS 屬性引用self->,self.xx與_xx的區(qū)別

 在iOS開(kāi)發(fā)過(guò)程中,我們用@proprety聲明一個(gè)屬性后,在代碼中我們可以用self.xx與_xx來(lái)獲取到這個(gè)屬性。但是一直有一個(gè)疑惑,那就是這兩個(gè)之間有什么區(qū)別呢?最初我一直覺(jué)得這兩個(gè)之間沒(méi)什么區(qū)別的,直到有一次,我發(fā)現(xiàn)自己明明對(duì)聲明的屬性進(jìn)行了賦值,但是在使用_xx引用時(shí)發(fā)現(xiàn)為nil,這才引起我的注意。所以,今天在這里對(duì)這個(gè)問(wèn)題進(jìn)行統(tǒng)一的一個(gè)說(shuō)明和學(xué)習(xí)。

1?@property 與 @synthesize

  在說(shuō)self.xx與_xx之前,我們先了解一下@property 以及 @synthesize之間的區(qū)別和聯(lián)系,說(shuō)到@property 以及 @synthesize,我們就不得不提到iOS中 成員變量和屬性 之間的區(qū)別和聯(lián)系了。

接觸iOS的人都知道,@property聲明的屬性默認(rèn)會(huì)生成一個(gè)_類型的成員變量,同時(shí)也會(huì)生成setter/getter方法。但這只是在iOS5之后,蘋(píng)果推出的一個(gè)新機(jī)制??蠢洗a時(shí),經(jīng)??吹揭粋€(gè)大括號(hào)里面定義了成員變量,同時(shí)用了@property聲明,而且還在@implementation中使用@synthesize方法,就像下面的代碼這樣:

其實(shí),發(fā)生這種狀況根本原因是蘋(píng)果將默認(rèn)編譯器從GCC轉(zhuǎn)換為L(zhǎng)LVM(low level virtual machine),才不再需要為屬性聲明實(shí)例變量了。在沒(méi)有更改之前,屬性的正常寫(xiě)法需要成員變量 + @property + @synthesize 成員變量?三個(gè)步驟。

如果我們只寫(xiě)成員變量+ @property:


  但更換為L(zhǎng)LVM之后,編譯器在編譯過(guò)程中發(fā)現(xiàn)沒(méi)有新的實(shí)例變量后,就會(huì)生成一個(gè)下劃線開(kāi)頭的實(shí)例變量。因此現(xiàn)在我們不必在聲明一個(gè)實(shí)例變量。(注意:==是不必要,不是不可以==)當(dāng)然我們也熟知,@property聲明的屬性不僅僅默認(rèn)給我們生成一個(gè)_類型的成員變量,同時(shí)也會(huì)生成setter/getter方法。在.m文件中,編譯器也會(huì)自動(dòng)的生成一個(gè)成員變量_myString。那么在.m文件中可以直接的使用_myString成員變量,也可以通過(guò)屬性self.myString.都是一樣的。注意這里的self.myString其實(shí)是調(diào)用的myString屬性的setter/getter方法。

此外,如果我們?cè)僮钚碌拇a中聲明一個(gè)成員變量,如下代碼所示,那么我們只是聲明了一個(gè)成員變量,并沒(méi)有setter/getter方法。所以訪問(wèn)成員變量時(shí),可以直接訪問(wèn)name,也可以像C++一樣用self->name來(lái)訪問(wèn),但絕對(duì)不能用self.name來(lái)訪問(wèn)。


  從Xcode4.4以后,即iOS的@property已經(jīng)獨(dú)攬了@synthesize的功能主要有三個(gè)作用:

生成了成員變量get/set方法的聲明

生成了私有的帶下劃線的的成員變量因此子類不可以直接訪問(wèn),但是可以通過(guò)get/set方法訪問(wèn)。那么如果想讓定義的成員變量讓子類直接訪問(wèn)那么只能在.h文件中定義成員變量了,因?yàn)樗J(rèn)是@protected

生成了get/set方法的實(shí)現(xiàn)

值得注意的是: ?

如果已經(jīng)手動(dòng)實(shí)現(xiàn)了get和set方法(兩個(gè)都實(shí)現(xiàn))的話Xcode不會(huì)再自動(dòng)生成帶有下劃線的私有成員變量了?

因?yàn)閤Code自動(dòng)生成成員變量的目的就是為了根據(jù)成員變量而生成get/set方法的,但是如果get和set方法缺一個(gè)的話都會(huì)生成帶下劃線的變量

2?self.xx與_xx

上面我們說(shuō)到了屬性與成員變量、@property 以及 @synthesize之間的聯(lián)系與區(qū)別。同時(shí),我們提到了self.xx和_xx的一點(diǎn)區(qū)別,其中self.xx是調(diào)用的xx屬性的get/set方法,而_xx則只是使用成員變量_xx,并不會(huì)調(diào)用get/set方法。兩者的更深層次的區(qū)別在于,通過(guò)存取方法訪問(wèn)比直接訪問(wèn)多做了一些其他的事情(例如內(nèi)存管理,復(fù)制值等),例如如果屬性在@property中屬性的修飾符有retain,那么當(dāng)使用self.xx的時(shí)候相應(yīng)的屬性的引用計(jì)數(shù)器由于生成了setter方法而進(jìn)行加1操作,此時(shí)的retaincount為2。

擴(kuò)展:很多人覺(jué)得OC中的點(diǎn)語(yǔ)法比較奇怪,實(shí)際是OC設(shè)計(jì)人員有意為之。

點(diǎn)表達(dá)式(.)看起來(lái)與C語(yǔ)言中的結(jié)構(gòu)體訪問(wèn)以及java語(yǔ)言匯總的對(duì)象訪問(wèn)有點(diǎn)類似,如果點(diǎn)表達(dá)式出現(xiàn)在等號(hào)=左邊,調(diào)用該屬性名稱的setter方法。如果點(diǎn)表達(dá)式出現(xiàn)在=右邊,調(diào)用該屬性名稱的getter方法。

OC中點(diǎn)表達(dá)式(.)其實(shí)就是調(diào)用對(duì)象的setter和getter方法的一種快捷方式,self.myString = @"張三";實(shí)際就是[self setmyString:@"張三"];

最后說(shuō)一下容易出現(xiàn)的問(wèn)題的地方,根據(jù)我個(gè)人的經(jīng)驗(yàn),

最容易出問(wèn)題的地方就是對(duì)屬性xx或成員變量_xx的初始化的地方和調(diào)用時(shí)機(jī),直接通過(guò)例子來(lái)看,我們將屬性和實(shí)例變量的初始化放在重寫(xiě)的get方法中,于是我們?cè)? (void)viewDidLoad中使用_invoiceInfoImageView來(lái)進(jìn)行布局時(shí),實(shí)際上因?yàn)樵谶@之前也沒(méi)有調(diào)用invoiceInfoImageView的get方法,所以此時(shí)invoiceInfoImageView的值其實(shí)為nil,界面上是空白的。


?  如果我們?cè)?使用self.xx來(lái)調(diào)用變量,則會(huì)調(diào)用invoiceInfoImageView的get方法,進(jìn)行初始化,界面布局將會(huì)顯示我們想要的圖片。此外,如果我們?cè)偈褂胈xx之前用self.xx調(diào)用過(guò)變量invoiceInfoImageView,則同樣會(huì)調(diào)用其get方法從而觸發(fā)invoiceInfoImageView的初始化,這樣也不會(huì)影響布局。


還有一點(diǎn)值得注意的就是我們前面提到過(guò)的,如果我們同時(shí)手動(dòng)重寫(xiě)了一個(gè)屬性的get和set方法的話,Xcode不會(huì)再自動(dòng)生成帶有下劃線的私有成員變量了。如下圖所示,在我們只定義了get方法時(shí)一切都沒(méi)有問(wèn)題,但是一旦我們又重寫(xiě)set方法,會(huì)發(fā)現(xiàn)用到_xx的地方就會(huì)報(bào)錯(cuò)。


轉(zhuǎn)發(fā)參考文章:

iOS學(xué)習(xí)——屬性引用self.xx與_xx的區(qū)別 - mukekeheart - 博客園

?著作權(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)容

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