为属性创建自己的setter时的无限递归

时间:2013-04-17 19:18:13

标签: objective-c infinite-loop setter

我在Objective-C中偶然发现了一些奇怪的行为。 我有一个main.m:

#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上的clang或OSX上的Xcode编译此代码时,setAVariable:会触发无限递归。 我想知道这是否是clang / Objective-C中的错误。

1 个答案:

答案 0 :(得分:7)

这是预期的。您正在设置器中访问您的setter。

self.aVariable = bVariable实际上正在调用[self setAVariable:bVariable],因此递归。点语法就是这样,一种特殊的语法,实际上只是实际setter方法的简写。在编写自己的setter方法时,应该访问支持实例变量,而不是属性本身。 E.g。

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

通常的做法是为实例变量使用前导下划线,以便在您直接访问实例变量时与属性(通过getter和setter来获取后备实例变量)很容易识别。

此外,最佳做法是使用#import而不是#include,因为#import只包含一次文件,即使同一文件有多个#import语句,也可能加快编译时间。