iphone - 了解 Objective-C 范围问题

标签 iphone objective-c ios ipad

以下是 View Controller 实现的片段:

- (void)myOtherAwesomeMethod
{
    [self myAwesomeMethod]; // Compile ERROR here: Receiver type for instance message does not declare a method with selector
}

- (void)myAwesomeMethod
{
    NSLog(@"%@", @"Calling my awesome method...");
}

- (void)viewDidLoad
{
    [self myAwesomeMethod];

    [self myOtherAwesomeMethod];
}

我的头文件中没有声明myAwesomeMethod方法,但是为什么我可以在viewDidLoad中调用myAwesomeMethod,但不能在 myOtherAwesomeMethod 中?

我知道这个错误的解决方案是在我的头文件中声明该方法,但我想了解为什么会这样。

最佳答案

在 C 中,规则是:您必须在使用它之前声明它。

文件是从上到下编译的。所以这是您的代码中发生的事情:

  1. 编译器读取类的@interface 声明。既然你说这两个方法都没有在头文件中声明,那么它们都不在符号表中。

    你的符号表包含:还没有

  2. 编译器读取myAwesomeMethod 的方法定义。您还没有声明它,所以它被添加到符号表中。该方法的主体包含对 NSLog 的调用,该调用很久以前就在 Apple 提供给您的 header 中进行了声明。

    您的符号表包含:myAwesomeMethod

  3. 编译器读取viewDidLoad的方法定义;它实际上是在父类(super class)的头文件中声明的。方法的主体包含对 myAwesomeMethod 的调用,已找到!它还包含对 myOtherAwesomeMethod 的调用。没听说过!

    现在,这不是错误,因为它仍然可以生成代码来进行调用。它可以根据您的使用方式推断参数类型(在本例中,没有参数)。但是,它不能确定返回类型(只是因为您不使用返回值并不意味着没有返回值)。因此它继续假设调用返回 id 并生成警告。

    您的符号表包含:myAwesomeMethod

  4. 最后,编译器读取myOtherAwesomeMethod 的方法定义。它被添加到符号表中。它编译主体,其中包含对表中的 myAwesomeMethod 的调用。一切皆大欢喜。

    在文件末尾,您的符号表包含:myAwesomeMethodmyOtherAwesomeMethod

如果您来自 Java 这样的语言,这可能看起来很愚蠢,但那是因为 Java 的工作方式与 C 不同。在 Java 中,源代码是一步编译和链接的;如果没有可用的源代码或类文件,则无法编译引用另一个类的类。这可能很麻烦,但另一方面,除了定义之外,您永远不需要声明。

在C语言中,编译和链接是不同的步骤。编译器只生成引用可能在别处定义的符号的目标代码;它使用声明来确保生成正确的代码。链接器负责将所有这些符号与其他静态或动态库中的定义进行匹配。

在 Objective-C 中,链接器实际上并不知道/关心 Objective-C 消息,因为在编译时/链接时无法知道对象是否可以响应消息。因此它将责任推给了运行时,如果您在没有方法定义的情况下走得太远,它会抛出异常。

关于iphone - 了解 Objective-C 范围问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6755769/

相关文章:

iphone - 从 iPhone 地址簿中获取一个人的图像

ios - 皱缩的布局

android - 为什么我不能用 Titanium 创建基本窗口?

ios - 当 NSAttributedString 属性的范围嵌套/重叠时,它们会堆叠吗?

iphone - 使用场景转换动画化 UIKit 项目

ios - 在 TableView 中从底部添加新数据

iphone - AVAudioPlayer 音量淡出

ios - 我可以查明单元格何时排队吗?

objective-c - 从 CGImageRef 创建 NSImage 会导致图像像素大小加倍

ios - 在核心数据的持久存储之间复制记录?