前提
對以下內(nèi)容的理解請謹記Objective-C很重要的的一個特性:消息傳遞。眾所周知,在OC中我們使用[]“調(diào)用一個對象的方法”,但實際上這里使用“調(diào)用”是不準確的,更加嚴謹?shù)睦斫馐牵覀兪窍蛟搶ο蟀l(fā)送了一條消息,例如[object doSomething];
這會使OC在運行時向object發(fā)送一條消息,而object對象便會在實現(xiàn)文件里匹配一個名字叫做doSomething的方法,如果這時候?qū)崿F(xiàn)文件不存在名稱為doSomething的無參方法,程序運行就會出錯。有則執(zhí)行這個方法。另外一個比較常用的是在OC 2.0以后,OC引進了“點語法”的特性,允許我們像C++,java一樣通過“對象.屬性”的形式來訪問對象的屬性,而沒有必要再像從前一樣使用[object 屬性名]
訪問屬性,使用[object set屬性名]
修改屬性。但這里我們需要知道的是,雖然我們使用點語法來訪問修改屬性,但OC運行時執(zhí)行的依舊還是屬性對應的“存取方法”,只是有些時候,編譯器在編譯階段自動幫我們生成了屬性對應的存取方法。
把實例變量聲明在{}
把實例變量聲明在{}引發(fā)的問題
請看以下代碼
@interface MyObject : NSObject{
NSString *firstName;
NSString *lastName;
}
@end
@implementation MyObject
@end
以上的MyObject類在{}里聲明了兩個實例變量。此時,你可以在類內(nèi)通過“實例變量名”來訪問該實例變量,如
firstName = @"myName";
lastName = firstName;
但是你不能使用諸如
//類內(nèi)訪問
[self firstName]
[self setFirstName]
//類外訪問
[object firstName]
[object setFirstName]
來訪問實例變量。因為這種情況下編譯器是不會幫你自動生成這兩個實例變量對應的“存取方法”的。同樣的原因,你也無法通過“點語法”:
//類內(nèi)
self.firstName
//類外
object.firstName
來訪問實例變量。因為“點語法”最后也會轉(zhuǎn)換成消息傳遞來實現(xiàn)的(前文已說明)。
解決把實例變量聲明在{}引發(fā)的問題
知道了問題的本質(zhì),要解決以上的問題,自然是在類中把實例變量的“存取方法”的聲明(頭文件)和實現(xiàn)(實現(xiàn)文件)寫出來就好。
@property關鍵字
@property關鍵字的引入,就可以很方便的讓編譯器知道它需要自動生成相應實例變量的“存取方法”,并生成名為_屬性名
的實例變量。在這里也可以得到一個結(jié)論:屬性 最終還是通過實例變量來實現(xiàn)的。還是直接上代碼:
@interface MyObject : NSObject{
}
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation MyObject
@end
這種情況下就可以正常使用以上方法訪問實例變量(屬性)了:
//類內(nèi)訪問
[self firstName]
[self setFirstName]
self.firstName //點語法
//類外訪問
[object firstName]
[object setFirstName]
object.firstName //點語法
另外如果使用了readonly
關鍵字,編譯器只會自動生成get方法,不會生成set方法。
題后話
@property除了有本文所討論的作用,在內(nèi)存管理還有很大的作用,因有些同學會疑惑類變量應該聲明在哪里,本文只討論一下這個問題,其他小編就不延伸了。