2013-04-09 1 views
15

я код распределяемые в библиотеке, которая выглядит следующим образом:При каких условиях может instancesRespondToSelector: возвращает истину, но performSelector: сгенерирует исключение

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 

Это объясняет, почему код выполняется, но она, конечно, будет очень плохо , что нужно сделать. Есть ли способ, которым может возникнуть эта проблема, которая имеет смысл?

+0

Вы уверены, что ваш метод «JSONValue» возвращает словарь? Возможно, это ваша проблема. – Maggie

+0

@Maggie Не имеет значения, что возвращает метод, исключение вызвано * вызовом * методом. Тип возврата для метода 'JSONValue' -' id'. – ThomasW

+0

Вы уверены, что сторонний использует этот код с предложением 'if'? –

ответ

4

Я предполагаю, что вы не импортировали стороннюю библиотеку правильным способом. Обычно эти методы добавляются как категория в NSString, мне случилось, что я мог видеть файл .h, но .m не был скомпилирован. Вы можете проверить его внутри цели xcode -> фазы сборки -> скомпилировать источники. Или проверьте, есть ли у вас этот флаг внутри проекта -> Настройки сборки -> Другой флаг компоновщика = -all_load

+1

'-all_load' больше не требуется,' -ObjC' достаточно. Также это не объясняет, почему 'instanceRespondToSelector' возвращает true. –

+0

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

+1

Спросите их, могут ли они проверить или дать вам весь проект, у меня есть почти та же проблема, что и интеграция MKNetworkKit в новый проект. Я делал много раз, но вчера он просто не работал, я мог отправлять сообщения, но не реализовывать их в категориях этой библиотеки. Добавление флага -all-load все шло отлично. Для полноты я не отправлял replyToSelector сообщения, но автозаполнение и компоновщик строились нормально. – Andrea

0

Существует нечетная возможность: возможно, что performSelector сам по себе работает в другой среде с обратной связью, остаток кода. Не совсем (или даже приблизительно) уверен, как это может произойти.

+0

Не могли бы вы пояснить, что вы подразумеваете под «средой с загрузкой ссылок»? – ThomasW

+0

@ThomasW - Результаты построения связующего, исполняемого модуля, независимо от того, что вы хотите назвать. Терминология отличается от каждой платформы, и я не могу идти в ногу с ними. В частности, если некоторые части находятся в отдельном библиотечном модуле, возможно, что они не могут «видеть» все материалы в другом модуле или наоборот. –

+0

В любом случае, если это проблема, вероятно, было бы работать с jsonString для типа фиктивного интерфейса, который определяет JSONValue и выполняет вызов напрямую (или так же, как Objective-C делает любой вызов). –

7

NSString - это в основном class cluster и вызывает всевозможные осложнения ... вам действительно нужно спросить экземпляр, если он отвечает на селектор.

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 и компоновщик LLDB, различия ABI/Runtime?

+0

Я согласен с тем, что похоже, что это может быть связано с кластерами, но я не могу придумать никакого реального способа, которым это может быть проблемой. У вас есть конкретный пример того, как вы могли бы привести к описанному результату? Я предполагаю, что OP пытается избежать создания строки вообще, если не может быть JSONValue'd. (например, он имеет резерв, который включает в себя анализ данных напрямую) –

+0

хорошо, если категория находится на NSString и NSCFString на самом деле является суперклассом NSString –

+1

__NSCFString является подклассом NSString (NSMutableString, фактически), поэтому я до сих пор не вижу, как это может вызвать проблему. –

0

Убедитесь, что никто не swizzling функцию

4

Исключение не приходит непосредственно из среды выполнения Objective-C в ответ на отправку сообщения о том, что экземпляр не признает. Он исходит от -[NSObject doesNotRecognizeSelector:], который вызывается в конце различных способов поиска и переадресации методов.

Однако все, что угодно, может вызвать -doesNotRecognizeSelector:. Класс может «дезавуировать» унаследованный метод, переопределяя его и делая переопределение только вызывать -doesNotRecognizeSelector:. Поскольку documented, это приведет к исключению, которое вы видите, несмотря на то, что -respondsToSelector:+instancesRespondToSelector:) возвращается YES.

Я не мог вам сказать, почему __NSCFString делает это в случае вашего конечного пользователя. Является ли приложение, которое использует вашу библиотеку с помощью категорий или методов swizzling, чтобы изменить методы этого класса?

Кроме того, делает ли ваш журнал фактический захват трассировки стека в исключении? Это может быть информативным.