Давайте на минутку предположим, что компилятор включает метод:
@implementation AwesomeClass
- (void)doFoo OBJC_INLINE { // or some way to indicate "this is an inline method"
NSLog(@"doing foo!");
}
- (void)doBar {
[self doAwesomeStuff];
[self doFoo];
}
@end
так что -doBar
по существу становится:
- (void)doBar {
[self doAwesomeStuff];
{
NSLog(@"doing foo!");
}
}
Круто, похоже, что это будет быстрее, верно? Мы сохраняем себе целую дюжину инструкций, не звоня objc_msgSend
. Таким образом, вы упаковываете это и публикуете в Интернете в виде файла .a.
NSCleverCoder приходит и говорит «но я хочу, чтобы doFoo
сделал немного больше», поэтому он делает:
@interface SuperAwesomeClass : AwesomeClass @end
@implementation SuperAwesomeClass
- (void)doFoo {
NSLog(@"doing more foo!");
[super doFoo];
}
@end
Когда он пытается запустить это, он никогда не вызывается , потому что AwesomeClass
на самом деле никогда не вызывает метод -doFoo
.
«Но, - говорите вы, - это надуманный пример!»
Нет, это не так. В Objective-C это абсолютно законно делать в любой момент разработки или исполнения приложения. Я могу сделать это при написании кода. Черт возьми, я даже могу сделать это во время выполнения, используя objc_allocateClassPair
и class_addMethod
для динамического создания подкласса и добавления переопределения метода.
Я также могу реализовать реализации методов. Не нравится существующая реализация -doFoo
? Это круто; замените его своим. Ой, подожди; если метод был встроен, ваша новая реализация никогда не будет вызвана, потому что -doBar
никогда не вызывает метод -doFoo
.
В только раз я мог видеть, что это возможно, если бы был какой-то способ аннотировать метод как не подлежащий переопределению. Но нет способа сделать это , так что эта проблема спорная. И даже тогда это все равно будет плохой идеей; то, что компилятор не позволяет вам этого делать, не означает, что вы не можете обойти его во время выполнения. И снова вы столкнетесь с проблемами.