在Objective-C中,方法的绑定是否真的发生在"运行时"?

时间:2016-01-11 07:24:12

标签: ios objective-c oop dynamic binding

我听说Objective-C受到"消息传递机制的影响" SmallTalk。

  

与Smalltalk一样,Objective-C可以使用动态类型:对象可以   发送了未在其界面中指定的消息。这可以允许   提高灵活性,因为它允许对象捕获"一个   消息并将消息发送到可以响应的其他对象   适当的消息,或同样将消息发送给另一个消息   对象

我觉得像[anObject someMethod]这样的代码,someMethod与机器代码的绑定可能会在运行时发生..

因此,我写了一个这样的演示:

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    @private char *name;
}
@property (readwrite, assign) char *name;
- (void)sayHello;
@end

@implementation Person
@synthesize name;

- (void)sayHello {
    printf("Hello, my name is %s!\n", [self name]);
}


@end

int main() {
    Person *brad = [Person new];
    brad.name = "Brad Cox";
    [brad sayHello];
    [brad sayHelloTest];


}

我尝试[brad sayHelloTest]brad发送sayHelloTest brad无法知道如何处理的消息。我希望错误不会发生在编译时..

但是,编译器仍会抛出错误:

main.m:24:11: error: instance method '-sayHelloTest' not found (return type defaults to 'id') [-Werror,-Wobjc-method-access]
    [brad sayHelloTest];
          ^~~~~~~~~~~~
main.m:3:12: note: receiver is instance of class declared here
@interface Person : NSObject {
           ^

[(id)brad sayHelloTest]更改为[(id)brad sayHelloTest];也不起作用..(编译命令为clang -Wall -Werror -g -v main.m -lobjc -framework Foundation -o main

在Objective-C中,方法的绑定是否真的发生在&#34;运行时&#34;?如果是这样,为什么会出现这样的编译器错误?

如果绑定没有发生在&#34;运行时&#34;,为什么&#34; Objective-C&#34;叫做#34;动态打字语言&#34;?

有没有人对此有任何想法?

4 个答案:

答案 0 :(得分:0)

编译器的一项工作是在编译时捕获尽可能多的错误。如果它可以告诉调用在运行时失败,通常会让它抱怨。

您可以通过强制转换来抑制此操作,以显示运行时解析正在发生:

[(id)brad sayHelloTest];

答案 1 :(得分:0)

因为IDE可以从上下文中推断出明显的错误。

当你写if (a = 1)时,你会收到警告。一个好的IDE应该帮助你尽早发现错误。

答案 2 :(得分:-1)

仅在过去五年内才有become a compiler error因为没有已知的方法声明。它与Automatic Reference Counting有关。在ARC下,编译器现在负责Cocoa使用的基于引用计数的内存管理。

鉴于责任,它必须能够在发送之前查看任何消息的方法声明,以便它知道哪些保留和发布是合适的。

方法解决方案(在类上查找方法)仍然在运行时发生,并且 - 特别是如果禁用ARC - 您仍然可以利用message forwarding

有关ARC的要求的一种方法是由Marcelo Cantos给出 - 将接收器投射到id。另一种方法是使用performSelector:。第三个 - 虽然我不推荐它 - 是直接使用objc_msgSend()

请注意,该方法的“绑定”在编译时发生并始终。在定义类时,方法与类相关联。 消息与方法不同,它们是在运行时解析到方法。

答案 3 :(得分:-1)

我终于找到了原因..

在编译期间抛出错误,因为包含-Werror标记,这会将警告转换为错误 ..

http://clang.llvm.org/docs/UsersManual.html#cmdoption-Werror

删除-Werror标志后,一切都按预期工作,错误只在运行时发生。