当我在学习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;
}
这次我收到了一个错误。我只能通过在头文件中添加声明来修复它。所以在这种情况下需要声明(当然)。
必须有一些我不熟悉的事情发生在幕后。谁能解释一下这背后的机制呢?
提前致谢。
编辑:重写问题,让代表获得神奇的投票权,以便我可以投票或者投票给别人的答案。
答案 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使用运行时绑定,因此方法调用直到执行时才解析。