2013-04-17 37 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语句,也只会包含文件一次,这可能会加快编译时间。