В каких условиях могут быть экземплярыRespondToSelector: вернуть true, но выполнитьSelector: выставить исключение
У меня есть код, распространяемый в библиотеке, который выглядит так:
if ([[NSString class] instancesRespondToSelector: @selector(JSONValue)]) {
NSString *jsonString = [[[NSString alloc] initWithData: jsonData encoding: NSUTF8StringEncoding] autorelease];
dict = [jsonString performSelector: @selector(JSONValue)];
}
По какой-то причине возникает исключение -[__NSCFString JSONValue]: unrecognized selector sent to instance
при вызове метода performSelector:
. Это код, который распространяется в библиотеке, которую я написал, но я не могу воспроизвести или отладить ее сам. Вместо этого сторонняя сторона сообщает об этой проблеме. При каких условиях может instancesRespondToSelector:
при вызове метода с помощью performSelector:
выполнить исключение?
изменить
Есть случай, который мог бы объяснить, почему это происходит, но это не имеет смысла. Если разработчики должны были сделать что-то вроде этого:
@implementation NSString (OurHappyCategory)
+ (BOOL)instancesRespondToSelector:(SEL)aSelector
{
return YES;
}
@end
Это объясняет, почему код выполняется, но, конечно, это будет очень плохо. Есть ли способ, которым может возникнуть эта проблема, которая имеет смысл?
Ответы
Ответ 1
NSString представляет собой кластер классов и вызывает всевозможные осложнения... вам действительно нужно спросить экземпляр, если он отвечает на селектор.
NSString *jsonString = [[[NSString alloc] initWithData: jsonData encoding: NSUTF8StringEncoding] autorelease];
if ([jsonString respondsToSelector: @selector(JSONValue)]) {
dict = [jsonString performSelector: @selector(JSONValue)];
}
но ваша проблема, вероятно, связана с компиляцией или связыванием расширения... если категория добавлена в библиотеку, тогда вам нужно будет побрызгать флагом -ObjC
.
EDIT:
Я немного поработал над воспроизведением этой проблемы... которой я не могу...
есть ли у вас дополнительная информация.. например, это сбой, возникающий только на симуляторе или только на устройстве, iOS 4.x, GNU linker vs LLDB linker, различия ABI/Runtime?
Ответ 2
Я предполагаю, что вы не импортировали стороннюю библиотеку правильно. Обычно эти методы добавляются как категория в NSString, мне случилось, что я мог видеть файл .h, но .m не был скомпилирован. Вы можете проверить его внутри цели xcode → фазы сборки → скомпилировать источники. Или проверьте, есть ли у вас этот флаг внутри Project → Build Settings → Other linker flag = -all_load
Ответ 3
Исключение не происходит непосредственно из среды выполнения Objective-C в ответ на отправку сообщения, которое экземпляр не распознает. Он исходит из -[NSObject doesNotRecognizeSelector:]
, который вызывается в конце различных способов поиска и механизмов переадресации.
Однако все, что угодно, может вызвать -doesNotRecognizeSelector:
. Класс может "дезавуировать" унаследованный метод, переопределяя его и делая переопределение просто вызывать -doesNotRecognizeSelector:
. Поскольку документировано, это приведет к тому, что вы видите, несмотря на то, что -respondsToSelector:
(и +instancesRespondToSelector:
) возвращает YES
.
Я не мог сказать вам, почему __NSCFString
делает это в вашем случае конечного пользователя. Приложение, использующее вашу библиотеку с помощью категорий или методов swizzling, чтобы изменить методы этого класса?
Кроме того, показывает ли ваш журнал фактический захват трассировки стека в исключении? Это может быть информативным.
Ответ 4
Существует нечетная возможность: может быть, что performSelector
сам каким-то образом выполняется в другой среде с загрузкой ссылок, чем остальная часть кода. Не совсем (или даже приблизительно) уверен, как это может произойти.
Ответ 5
Удостоверьтесь, что никто не выполняет функцию