点语法与getter =的方法语法

时间:2012-02-09 22:40:26

标签: objective-c

我不确定这个问题有多少用处,但对我来说似乎很有意思......

我认为使用property / synthesize语句等同于我创建getter / setter。因此

// .h
@property (nonatomic) BOOL on;

// .m
@synthesize on = _on;

// In my mind synthesizes the following methods

// - (BOOL)on;
// - (void)setOn:(BOOL)on;

但是,如果我将声明更改为以下内容:

                              v
@property (nonatomic, getter=isOn) BOOL on;

@synthesize on = _on;

// In my mind synthesizes the following

// - (BOOL)isOn;
// - (void)setOn:(BOOL)on;

然后给出上面的内容我重写了getter,所以我知道它何时被调用:

- (BOOL)isOn;
{
    NSLog(@"I was called");
    return _on;
}

现在在实例(myClass)上调用以下内容会导致:

NSLog(@"%d", [myClass isOn]);

//=> 2012-02-09 22:18:04.818 Untitled[1569:707] I was called
//=> 2012-02-09 22:18:04.820 Untitled[1569:707] 1

NSLog(@"%d", myClass.isOn);

//=> 2012-02-09 22:18:24.859 Untitled[1599:707] I was called
//=> 2012-02-09 22:18:24.861 Untitled[1599:707] 1

NSLog(@"%d", myClass.on);         // This is the one I didn't expect to work

//=> 2012-02-09 22:18:55.568 Untitled[1629:707] I was called
//=> 2012-02-09 22:18:55.570 Untitled[1629:707] 1

我一直认为,如果我在这个意义上使用了一个属性,那么在表单中使用带有点语法的getter / setter是完全有效的

myClass.isOn;
myClass.on = on;

从另一个question建议使用点语法时我应该使用如下属性名称:

myClass.on   // Correct
myClass.isOn // Incorrect

虽然这样做有点不合逻辑,因为我知道没有基础方法- (BOOL)on而是映射到- (BOOL)isOn

我的问题是(使用后一个例子)

  • 这是一个错误还是应该myClass.on真正默默地更改为调用- (BOOL)isOn
  • 从语义上讲,我正在访问不调用行为的状态,所以我目前使用的点语法是否正确? (例如myClass.isOn

更新

虽然没有人明确说过,但我有理由认为使用.isOn是不好的形式,因为无论在引擎盖下调用相同的方法,语义isOn都在问一个问题,是更多的行为而不是国家。

但是我仍然不清楚“神奇”布线在哪里将myClass.on的呼叫转为[myClass isOn]


更新2

在查看文档后,我在Declared Properties找到了此部分。使用以下代码,我可以检查类的属性:

id MyClass = objc_getClass("MyClass");
unsigned int outCount, i;

objc_property_t *properties = class_copyPropertyList(MyClass, &outCount);
for (i = 0; i < outCount; i++) {
    objc_property_t property = properties[i];
    NSLog(@"Name: %s, attributes: %s\n", property_getName(property), property_getAttributes(property));
}

//=> 2012-02-10 07:10:28.333 Untitled[934:707] Name: on, attributes: Tc,GisOn,V_on

所以我们有以下属性:

  • name = on
  • type = char(Tc)
  • getter = isOn(GisOn)
  • variable = _on(V_on)

在运行时可以获得所有这些信息,有一点问题是这个查找是在运行时还是编译时完成的,就像一些答案所示?

4 个答案:

答案 0 :(得分:4)

  

但是我仍然不清楚“神奇”布线在哪里将myClass.on的调用转换为[myClass isOn]

在获取上下文中编译obj.name时,逻辑肯定如下:

if(there is an accessible @property for name in scope)
{
   if(there is a custom getter specified)
      compile "[obj customGetter]"
   else
      compile "[obj name]"
}
else if (there is an an accessible instance method name in scope)
   compile "[obj name]"
else
{
   compile "[obj name]"
   warn obj may not respond to name
}

语言/执行环境还可以通过其他方式处理自定义getter名称,但是假设Obj-C将声明放在标题中(这是公共的),上面就可以很好地猜测自定义getter逻辑的执行位置 - 编制呼叫站点时。

答案 1 :(得分:3)

从您的实验中我们可以推断出点语法解释如下:

  • 有这个名字的财产吗?如果是,它是否具有指定的getter / setter名称?如果是这样,让我们​​称之为该方法。
  • 否则,组成一个合适的方法名称(如果我们正在设置则直接,如果我们设置则设置为setXX)并将其丢弃到接收器。

例如,您可以尝试对NSArray实例使用.count。在憎恶警察开门之前,你可能有时间看到它有效。

要真正回答您的问题,我认为点符号只应用于访问属性,在这种情况下,您应该使用界面中声明的属性名称。因此,对于UISwitch来说。我不知道为什么没有在synthesize语句中给出getter名称而不是属性声明,它似乎属于实现而不是接口。

答案 2 :(得分:2)

关于点符号,请允许我引用Aaron Hillegass(Mac OSX的可可编程,第3版):

&#34;总的来说,我认为这是对语言的一种相当愚蠢的补充,因为我们已经有了发送消息的语法。&#34;

当你有一个成员变量,并且你的这个变量的getter被称为isOn然后.on和.isOn是两种非常不同的东西。通过使用getter(也可能是一个setter),你将坚持&#34;信息隐藏&#34;承诺,而通过使用直接访问成员变量,你不会。 Cocoa因为依赖惯例而不会执行这些事情。由您来决定哪种方式适合您。考虑到惯例,你必须坚持使用setter和getter - 不管你给他们什么名字。

答案 3 :(得分:1)

属性声明只是常规方法声明的简写。 E.g:

@property int color;
@property (getter=isOn) BOOL on;

成为这些方法声明:

- (int)color;
- (void)setColor:(int)value;
- (BOOL)isOn;
- (void)setOn:(BOOL)on;

您可以像其他任何方法一样调用这些方法:

[foo color];
[foo isOn];

同样,点符号只是用于调用普通旧方法的非正式简写。例如:

x = @"Hello".length;
x = foo.on;
x = foo.isOn;

变为

x = [@"Hello" length];
x = [foo isOn];
x = [foo isOn];

请注意,即使NSString实际上没有声明名为“length”的属性,@"Hello".length仍然有效。默认情况下,foo.bar始终会扩展为[foo bar] ,除非 bar已声明为具有自定义getter的属性。如果bar碰巧是有效方法的名称,那么它将正常工作。

同样,在您的示例foo.isOn中,即使您实际上没有声明名为“isOn”的属性也可以。相反,“isOn”是恰好是“on”属性的getter方法的方法名称。

因此,虽然foo.isOn可能有用,但它被视为不良格式,因为isOn实际上并不是该属性的名称。

你不能做的是:

x = [foo on]; // Error

因为您从未声明on方法。