iOS - 为什么不在头文件中声明IBAction方法呢?

时间:2013-12-26 21:06:12

标签: ios objective-c

当我在学习Start Developing iOS Apps Today时,我注意到这个方法unwindToList:的返回类型为IBAction,不需要首先在头文件中声明传递编译或者运行正常。由于我可以使用任何名称作为方法名称,我认为这与协议无关。

以下是示例代码:

XYZToDoListViewController.h

#import <UIKit/UIKit.h>

@interface XYZToDoListViewController : UITableViewController

@end

XYZToDoListViewController.m

@implementation XYZToDoListViewController

- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{

}

// other implementations..

@end

在此之后,在Interface Builder中,如下图所示,我可以控制 - 将控件拖到退出图标,将此方法注册为控件的操作。令我惊讶的是,单击“运行”按钮后没有发生错误。

我是Obj-C的新手,这让我大吃一惊。我对C有一点了解。在C中,我必须通过在使用它之前声明或定义它来确认编译每个函数。

所以我创建了一个小项目,看看我是否可以在Obj-C中首先定义一个没有声明的方法。这是我测试的代码:

// XYZFoo.h
#import <Foundation/Foundation.h>

@interface XYZFoo : NSObject

@end

.m文件:

// XYZFoo.m
#import "XYZFoo.h"

@implementation XYZFoo
- (void)bar {
    NSLog(@"hello, world");
}
@end

main.m文件:

// main.m
#import <Foundation/Foundation.h>
#import "XYZFoo.h"

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

    @autoreleasepool {

        XYZFoo *foo = [[XYZFoo alloc] init];
        [foo bar];

    }
    return 0;
}

这次我收到了一个错误。我只能通过在头文件中添加声明来修复它。所以在这种情况下需要声明(当然)。

必须有一些我不熟悉的事情发生在幕后。谁能解释一下这背后的机制呢?

提前致谢。

编辑:重写问题,让代表获得神奇的投票权,以便我可以投票或者投票给别人的答案。

drag to exit icon

3 个答案:

答案 0 :(得分:2)

Xcode与此无关。

在您的代码中,您通过标准括号表示法显式调用对象上的方法。您告诉编译器有一个具有特定名称的方法(在编译时已知),并且您希望将该确切消息发送到该对象。为此,编译器当然需要声明。

但是,当您引用IBAction时,我假设您的意思是由各种UI对象(如按钮或控件)调用的回调方法。 (快速查看Apple的文档后,我发现“取消”按钮调用了此方法。)

这些方法是使用一些其他机制调用的,借助于Objective-C的一个名为reflection的特性,可以在运行时调用动态命名的方法。例如,我可以想象在UIControl类(UIButton的超类)中的某个地方,有一个内部方法来处理这样的所有动作的调度:

- (void)dispatchActions
{
    for (id target in self.targets) {
        SEL selector = [self selectorForTarget:target]; // an imaginary method...
        [target performSelector:selector withObject:self];
    }
}

因此,这将使用performSelector:withObject:完全动态地将所有消息发送到目标。要做到这一点,不需要声明方法,因为编译器并没有真正看到它们被调用。这只是要求发送消息的运行时。所有编译器需求都是performSelector:withObject:方法的签名,该方法可用。

答案 1 :(得分:1)

编译器不会为操作生成声明。以下是发生的情况:将控件连接到操作时Interface Builder会在故事板中记录有关操作选择器的信息。

当storyboad的视图被实例化时,storyboard运行时调用新创建的控件的addTarget:action:forControlEvents:方法将它们连接到那些目标(有关详细信息,请参阅此链接https://developer.apple.com/library/mac/documentation/cocoa/conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW8)。故事板运行时使用故事板文件内容来连接操作,因此它不需要方法声明。

另一方面,当从类外部编译器调用方法时,检查方法是否已在头文件中的某处声明,如果找不到声明,则发出 warning 以防止可能运行时错误。

答案 2 :(得分:0)

如果您希望能够控制 - 从按钮拖动到他们的操作,那么 DO 需要在标题中定义IBAction。方法声明中的“IBAction”关键字(在标题中)告诉IB有关作为操作连接的方法。如果没有IBAction声明,IB就不知道该方法。

通常当您尝试在.m文件中定义的另一个类中调用方法而不是.h文件时,会收到警告,而不是错误。如果忽略警告(一个坏主意),那么在运行时代码仍然有效,因为该方法确实存在。

Objective C使用运行时绑定,因此方法调用直到执行时才解析。