我刚刚开始阅读我的第一本 Objective-C 书,而且大部分内容都很清楚,但是我想了解为什么它教我首先在接口中声明一个方法,我尝试从接口中删除它并在实现中执行它部分和所有似乎都有效,所以我的问题是它是否重要,如果是,这有助于完成什么?
3 回答
它是 C。在头文件中声明函数/方法允许其他编译单元查看您的函数原型并基于它们进行编译。不过,Objective-C 是通过动态调度工作的,因此即使您没有在标头中声明方法,它仍然存在于运行时。当您调用一个方法时,它会在运行时解析,因此它是否在标头中并不重要。
唯一的问题是,如果您不在标头中包含该方法,编译器必须对返回和参数类型做出假设。它默认id
为 4 或 8 个字节,具体取决于您的架构,因此如果实际返回类型的大小不同(例如结构BOOL
等),您将遇到麻烦。
您必须在接口(标头)中声明您的方法以使其公开(可由/从其他类访问)。如果您仅在类内部使用方法,则不必在接口中声明它。
Objective-C 是一种高度动态的语言(和运行时),它尽可能推迟决策。
代码运行良好,因为在运行时对象确实响应了您指定的选择器。
但是,通过声明方法,您可以帮助 Objective-C 编译器帮助您检查在运行时不会遇到任何意外情况。
例如,参加以下课程:
@interface MDFoo : NSObject
- (void)blah;
@end
@implementation MDFoo
- (void)blah {
NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
- (void)boo {
NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
@end
假设在另一个控制器类中,您创建了一个实例MDFoo
并希望向它发送一些消息。
MDFoo *foo = [[MDFoo alloc] init];
[foo blah];
[foo boo]; // compiler warning
[foo yell]; // compiler warning
当你编译程序时,编译器应该给你一个警告,最后两个方法都找不到,并且一个实例MDFoo
可能不会响应这些选择器。
如果您随后运行该程序,则会记录以下内容:
foo[10540:303] [MDFoo blah]
foo[10540:303] [MDFoo boo]
foo[10540:303] -[MDFoo yell]: unrecognized selector sent to instance 0x1001082f0
foo[10540:303] *** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[MDFoo yell]:
unrecognized selector sent to instance 0x1001082f0'
所以在运行时,关于警告的boo
结果是什么都没有,但是关于警告yell
是正确的,并导致应用程序终止。
从设计的角度来看,这也是让其他对象知道可以调用哪些消息的方式。(请参阅Objective-C 编程语言:定义类 - 接口的角色)。