【问题标题】:Objective-C dot notation with class methods?带有类方法的Objective-C点表示法?
【发布时间】:2011-01-23 11:21:57
【问题描述】:

注意,我特别指的是点符号与类方法一起使用,而不是实例方法。

出于好奇,我想看看如果我尝试将 Objective-C 点符号语法与类方法一起使用会发生什么。我的实验如下:

#import <Foundation/Foundation.h>

static int _value = 8;

@interface Test : NSObject

+ (int) value;
+ (void) setValue:(int)value;

@end

@implementation Test

+ (int) value {
    return _value;
}

+ (void) setValue:(int)value {
    _value = value;
}

@end

int main(int argc, char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSLog(@"Test.value: %d", Test.value);
    NSLog(@"[Test value]: %d", [Test value]);

    Test.value = 20;
    NSLog(@"Test.value: %d", Test.value);
    NSLog(@"[Test value]: %d", [Test value]);

    [Test setValue:30];
    NSLog(@"Test.value: %d", Test.value);
    NSLog(@"[Test value]: %d", [Test value]);

    [pool release];

    return 0;
}

我惊讶地发现这是编译的,更不用说以我认为正确的行为执行了。这是在某处记录的,还是只是编译器的侥幸?

我在 Mac OS X 10.6 上使用 GCC 编译:

gcc --version: i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5659) 

compile using: gcc ObjCClassDotSyntax.m -framework Foundation -o ObjCClassDotSyntax
run: ./ObjCClassDotSyntax

output:
2010-03-03 17:33:07.342 test[33368:903] Test.value: 8
2010-03-03 17:33:07.346 test[33368:903] [Test value]: 8
2010-03-03 17:33:07.351 test[33368:903] Test.value: 20
2010-03-03 17:33:07.352 test[33368:903] [Test value]: 20
2010-03-03 17:33:07.353 test[33368:903] Test.value: 30
2010-03-03 17:33:07.353 test[33368:903] [Test value]: 30

【问题讨论】:

  • 而且,我想知道,当点语法用于类方法时,为什么 Xcode 不自动完成?如果它真的是语法糖,例如foo.prop纯粹翻译成[foo prop],那么Xcode就不应该区分类方法和实例方法。

标签: objective-c


【解决方案1】:

Underscore 库通过从类方法返回块进一步滥用此语法,导致代码如下:

NSArray *elements = Underscore.array(array)
    .flatten
    .uniq
    .unwrap;

要了解其工作原理,请查看Underscore.array 的定义:

+ (USArrayWrapper *(^)(NSArray *))array
{
    return ^(NSArray *array) {
        return [USArrayWrapper wrap:array];
    };
}

所以:

Underscore.array(array) 

...等价于:

NSArray *array = @[];
USArrayWrapper * (^arr)(NSArray *) = [Underscore array];
USArrayWrapper *result = arr(array);

【讨论】:

    【解决方案2】:

    在“邪恶但有效”类别中,众所周知,我偶尔会使用带有点符号的便捷构造函数,例如 NSMutableArray *myArray = NSMutableArray.array

    【讨论】:

    • 伙计,这完全是邪恶的。我不知道是赞成还是反对邪恶……
    • 当然你也可以做“myView.setNeedsDisplay;”或任何其他不带任何参数的消息。
    • 你太邪恶了,让我的程序员的心被你的想法感染了。我的老板会跪下来求我。所有看到我的代码并哭泣的人,因为我也将成为一个坏人。
    【解决方案3】:

    这是正确的行为。 foo.method[foo method] 的语法糖——具有相同语义的直接转换。同样foo.prop = bar[foo setProp:bar] 的语法糖,同样具有相同的语义。这种转换在编译器中实现。因此,您可以使用点符号来调用 foo.doSomething 中的 0 参数方法,而不是 [foo doSomething]。当然,如果你这样做,你就是邪恶

    被调用者是类实例这一事实并不重要,因为在 Objective-C 中,类也是对象。在类上使用点表示法会调用该类的无参数方法。

    Objective-C Programming Language 文档中描述了点符号。

    【讨论】:

    • 邪恶 +1。不过说真的,使用甜合成糖会不会不好,如果是,为什么?
    • @andy 不使用糖来调用非访问器方法的原因是它破坏了@properties 的语义。这在该语言中是合法的,但对于阅读您的代码的来说,这意味着与该代码的效果不同的东西。不酷。
    • @Eric 这不是真的!点符号适用于任何正确命名的访问器,即使在实例中也是如此。属性是与点表示法不同的概念。正如 Barry Wark 所说,foo.bar[foo bar] 完全相同——这适用于 foo 是类还是实例,以及 bar 是由 @synthesize 定义还是手动定义,或者即使 bar 是一个动作或其他非-访问器方法。
    • 我强烈反对邪恶的声明,或者至少要求排除一个例外。如果您有一个方法可以返回类似特性的属性(即名词,而不是动词),那么未来的程序员会更容易理解代码。仅计算一些值(名词)而不是改变值或改变状态的方法可以通过点接口更好地访问,以便快速理解代码。动词方法(通常会改变状态)应始终通过括号表示法访问。
    • 最初来自 Ruby,我认为“方法调用的点语法是邪恶的”的想法是荒谬的。但是现在我已经研究了大约 6 个月的 Objective-c,我遇到了我的第一个不正确使用点语法的例子,一开始我很困惑。我的偏好是我什至不会在访问器方法上使用它,我只会在@properties 上使用它。这样,我立即知道什么是属性,什么不是,而无需查看头文件。在我看来,这似乎是最务实的。
    猜你喜欢
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 2010-09-07
    相关资源
    最近更新 更多