2013-04-17 68 views
4

我偶然發現了Objective-C中的一些奇怪行爲。 我有一個的main.m:爲屬性創建我自己的setter時的無限遞歸

#include <Foundation/Foundation.h> 
#include "AClass.h" 

int main(int argc, char* argv[]) { 
    AClass* tmpClass = [[AClass alloc] init]; 
    [tmpClass setAVariable:12]; 
    return -1; 
} 

報頭AClass.h:

#include <Foundation/Foundation.h> 

@interface AClass: NSObject; 

-(void) setAVariable:(int) bVariable; 

@property int aVariable; 

@end 

和一個對應的實現文件AClass.m:

#include <Foundation/Foundation.h> 
#include <AClass.h> 

@implementation AClass 
@dynamic aVariable; 
int aVariable; 

-(void) setAVariable:(int)bVariable { 
    NSLog(@"foo:"); 
    self.aVariable = bVariable; 
} 

@end 

當編譯該代碼與任一在Linux上的鏗鏘聲或通過OSX上的Xcode​​觸發無限遞歸。 我不知道這是否是clang/Objective-C中的錯誤。

+1

你應該知道,你所聲稱的'aVariable'是一個全球性的,而不是你所期待的伊娃。它需要位於'@ implementation'塊頂部的大括號中:'@implementation AClass {int aVariable; }/*等*/@結束' –

+0

這是我的意圖:) –

回答

7

這是預期的。你正在訪問你的setter中的setter。

self.aVariable = bVariable實際上是調用[self setAVariable:bVariable],因此遞歸。點語法就是這樣一種特殊的語法,它實際上只是實際setter方法的簡寫。在編寫自己的setter方法時,應該訪問backing實例變量,而不是屬性本身。例如。

- (void) setAVariable:(int)bVariable { 
    NSLog(@"foo:"); 
    aVariable = bVariable; 
} 

是很常見的做法是使用一個前導下劃線爲您的實例變量,所以很容易,當你直接訪問實例變量與財產(其經過getter和setter才能到備份實例變量識別)。

此外,最好使用#import而不是#include作爲#import,即使同一個文件有多個#import語句,也只會包含文件一次,這可能會加快編譯時間。