iOS知識梳理 - Objective-C的@property、@synthesize和@dynamic

objc推薦咱們經過set/get方法訪問對象的屬性。很顯然,爲每個屬性手動添加set/get方法的聲明和實現是個性價比很低的重複勞動。所以,objc提供了一些關鍵字幫助咱們簡化這一過程。實際上就是這麼回事兒。html

@property

首先來看如今的property:xcode

例如:app

@interface ViewController : UIViewController
@property (nonatomic,assign) BOOL testVar;
@end

簡單理解,至關於聲明瞭成員變量_testVar,聲明瞭實現了set方法setTestVar、get方法testVar,等價於:ide

@interface ViewController : UIViewController
{
    BOOL _testVar;
}
- (void)setTestVar:(BOOL)newTestVar;
- (BOOL)testVar;
@end

@implementation ViewController
- (void)setTestVar:(BOOL)newTestVar
{
    _testVar = newTestVar;
}
- (BOOL)testVar
{
    return _testVar;
}
@end

@synthesize

@synthesize能夠指定set/get方法的實現。ui

1. 默認

默認地,@synthesize會生成一個同名的成員變量做爲set/get的目標。this

例如:atom

@interface ViewController : UIViewController
@property (nonatomic,assign) BOOL testVar;
@end
  
@implementation ViewController
@synthesize testVar;
@end

等價於:code

@interface ViewController : UIViewController
{
    BOOL testVar;
}
- (void)setTestVar:(BOOL)newTestVar;
- (BOOL)testVar;
@end

@implementation ViewController
- (void)setTestVar:(BOOL)newTestVar
{
    testVar = newTestVar;
}
- (BOOL)testVar
{
    return testVar;
}
@end

能夠看到,set/get方法指向了成員變量testVar,也不會再默認生成_testVarhtm

注意,不少人誤認爲@synthesize默認生成的成員變量是_testVar,據我所知這是不對的。對象

官方文檔

Important: If you use @synthesize without specifying an instance variable name, like this:

@synthesize firstName;

the instance variable will bear the same name as the property.

In this example, the instance variable will also be called firstName, without an underscore.

2. 指定

@synthesize也能夠指定一個成員變量做爲其set/get的目標。

例如:

@interface ViewController : UIViewController
{
    BOOL exampleVar;
}
@property (nonatomic,assign) BOOL testVar;
@end
  
@implementation ViewController
@synthesize testVar = exampleVar;
@end

等價於:

@interface ViewController : UIViewController
{
    BOOL exampleVar;
}
- (void)setTestVar:(BOOL)newTestVar;
- (BOOL)testVar;
@end

@implementation ViewController
- (void)setTestVar:(BOOL)newTestVar
{
    exampleVar = newTestVar;
}
- (BOOL)testVar
{
    return exampleVar;
}
@end

此時set/get方法就指向了成員變量exampleVar

特別的,能夠聲明並指定成員變量_testVar,例如:

@interface ViewController : UIViewController
{
    BOOL _testVar;
}
@property (nonatomic,assign) BOOL testVar;
@end

@implementation ViewController
@synthesize testVar = _testVar;
@end

這是最符合官方規範的作法:每一個屬性對應一個以_開頭的成員變量。

能夠看出,這種寫法跟本文第一部分,只寫一個@property的做用是同樣的。

一點歷史

其實,在xcode4.4(對應clang3.2/LLVM4.0)之前,顯式聲明_testVar@synthesize testVar = _testVar;是標準作法。那時候只寫個@property並不會給你帶來成員變量和set/get的實現。

如今的表現是編譯器把之前的標準作法化做默認行爲的結果。當咱們只聲明瞭@property而沒有實現對應的set/get方法時,編譯器會默認聲明_開頭的成員變量並補全set/get的實現。

一個真實案例

最近遇到的問題是一坨老代碼,裏面用了@synthesize可是彷佛不是很規範,後來維護的人看起來也不太熟悉這幾個關鍵字,照着前人的代碼瞎寫,最後代碼相似下面的:

@interface ViewController : UIViewController
{
    BOOL _testVar;
}
@property (nonatomic,assign) BOOL testVar;
@end

@implementation ViewController
@synthesize testVar;
- (void)viewDidLoad {
    [super viewDidLoad];
    self.testVar = YES;
    if(_testVar){
        [self doSomething];
    }
}
@end

能夠看到,代碼邏輯裏用_testVar去作條件判斷實際上是徹底無效的。

@dynamic

@dynamic的做用是告訴編譯器,此屬性對應的set/get方法將會被動態提供。

說得明白一點,其實@dynamic作了兩件事:

  1. set/get我會本身提供的,不用幫我生成了
  2. 我會動態提供,沒直接寫在這裏,編譯器別給我報錯

一般若是用到dynamic的話,這些方法會在消息轉發的時候處理,也能夠經過runtime的一些機制動態插入。這裏有一些例子。

通常開發中基本上不會用到。

相關文章
相關標籤/搜索