Компилятор Objective-C пропускает определение протокола

Я пишу пару классов, которые используют библиотеку времени выполнения Objective-C. Это включает в себя получение определений протокола во время выполнения на основе их имени. Однако оказывается, что протоколы, которые явно не приняты классом или не указаны в коде с использованием @protocol(ProtocolName), исключаются из компиляции и недоступны во время выполнения.

Пример:

@protocol MyProtocol <NSObject>

-(void)doSomething;

@end

//Где-то еще в коде

Protocol *protocol = NSProtocolFromString(@"MyProtocol"); 
// ^ value of "protocol" will be nil when I run the application!

//Однако, если я использую, делаю следующее:

Protocol *whyDoIHaveToDoThis = @protocol(MyProtocol);
Protocol *protocol = NSProtocolFromString(@"MyProtocol"); 
// ^ value of "protocol" will now be a pointer as expected when I run the application!

Кто-нибудь знает, почему это так, и даже лучше, как заставить компилятор включать определения протоколов, которые не используются во время компиляции, но которые мне позже понадобятся во время выполнения?


person Daniel Hall    schedule 07.02.2014    source источник
comment
Это то, как это работает. Как вы можете использовать протокол, если нет класса, который его принимает?   -  person Hot Licks    schedule 07.02.2014
comment
Этот ответ может быть полезен: stackoverflow.com/a/11533804/342620   -  person Gabriel Roth    schedule 07.02.2014
comment
Это ожидаемо. Компилятор не создает метаданных для объявления протокола и создает дублирующую копию метаданных в любом файле, который использует протокол (либо путем его принятия, либо путем записи выражения @protocol(ProtoName).   -  person Greg Parker    schedule 07.02.2014
comment
Всем спасибо за комментарии. @Hot Licks — протоколы можно анализировать и применять во время выполнения с помощью таких функций, как class_addProtocol(). Для библиотек, подключаемых модулей и других типов кода, которые должны взаимодействовать с неизвестным внешним кодом во время выполнения, важно, чтобы определения протоколов можно было искать на лету, даже если никакие внутренние объекты не приняли их во время компиляции. Я действительно удивлен, что определения протоколов просто так убраны, когда Objective-C — это динамический язык, предназначенный для работы с неизвестными типами, что в первую очередь является основным использованием протоколов.   -  person Daniel Hall    schedule 07.02.2014
comment
Но протокол в основном является просто документацией для компилятора, чтобы сообщить ему, какие методы доступны - у него нет реальной функции времени выполнения. class_copyMethodList сообщит вам, какие методы существуют во время выполнения.   -  person Hot Licks    schedule 07.02.2014


Ответы (1)


Вы можете заставить компилятор включить протокол, создав фиктивный метод, который не вызывается и использует его. Я делал это раньше:

void preserveProtocolFromBeingTrimmed()
{
     (void)@protocol(BrightnessProtocol);
}

Я вижу, что Apple использует это в своих Плагин FxBrightness из FxPlug SDK.

person user1118321    schedule 07.02.2014
comment
Спасибо! Я проголосовал за ссылку на пример кода Apple. Мой ожидаемый ответ - это то, что заставляет включать определения протокола, которые не используются во время компиляции, чего не было бы в случае использования описанного выше метода. Я надеюсь на что-то большее, вроде флага компилятора и т. д., который заставляет заголовки протоколов, включенные в качестве целей компиляции, не игнорироваться, если они не используются, но я понимаю, что такой флаг может не существовать, и ваше предложение может быть лучшим/единственным решением. Если лучшего ответа не будет, я приму ваш :) - person Daniel Hall; 07.02.2014