Метод вызова по категории, включенной из статической библиотеки iPhone, вызывает NSInvalidArgumentException

Я создал статическую библиотеку для размещения некоторых моих кодовых категорий.

У меня есть категория для UIView в "UIView-Extensions.h" с именем Extensions.

В этой категории есть метод:

- (void)fadeOutWithDelay:(CGFloat)delay duration:(CGFloat)duration;

Вызов этого метода отлично работает на симуляторе в конфигурации Debug.

Однако, если попытаться запустить приложение на устройстве, я получаю исключение NSInvalidArgumentException:

[UIView fadeOutWithDelay:duration:]: unrecognized selector sent to instance 0x1912b0
 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIView fadeOutWithDelay:duration:]: unrecognized selector sent to instance 0x1912b0

По какой-то причине UIView-Extensions.h не включается в сборки устройств.


Что я проверил/попробовал

Я попытался включить другую категорию для NSString и имел ту же проблему.

Другие файлы, такие как целые классы и функции, работают нормально. Это проблема с только с категориями.

Я сделал все чистые цели, которые не устранили проблему.

Я проверил проект статической библиотеки, категории включены в целевые группы "заголовки копий" и "компилировать источники".

Статическая библиотека включена в основную группу "link binary with library".

В другом проекте я добавил, что статическая библиотека работает нормально.

Я удалил и повторно добавил статическую библиотеку без везения

Флаг компоновщика

-ObjC установлен

Любые идеи?


nm output

libFJSCodeDebug.a(UIView-Extensions.o):
000004d4 t -[UIView(Extensions) changeColor:withDelay:duration:]
00000000 t -[UIView(Extensions) fadeInWithDelay:duration:]
000000dc t -[UIView(Extensions) fadeOutWithDelay:duration:]
00000abc t -[UIView(Extensions) firstResponder]
000006b0 t -[UIView(Extensions) hasSubviewOfClass:]
00000870 t -[UIView(Extensions) hasSubviewOfClass:thatContainsPoint:]
000005cc t -[UIView(Extensions) rotate:]
000002d8 t -[UIView(Extensions) shrinkToSize:withDelay:duration:]
000001b8 t -[UIView(Extensions) translateToFrame:delay:duration:]
         U _CGAffineTransformRotate
000004a8 t _CGPointMake
         U _CGRectContainsPoint
         U _NSLog
         U _OBJC_CLASS_$_UIColor
         U _OBJC_CLASS_$_UIView
         U ___CFConstantStringClassReference
         U ___addsf3vfp
         U ___divdf3vfp
         U ___divsf3vfp
         U ___extendsfdf2vfp
         U ___muldf3vfp
         U ___truncdfsf2vfp
         U _objc_enumerationMutation
         U _objc_msgSend
         U _objc_msgSend_stret
         U dyld_stub_binding_helper

Ответ 1

Единственным решением, которое работало, было включение:

"- all_load"

в других флагах компоновщика.

EDIT: Обязательно добавьте этот флаг в проект, включая статическую библиотеку, а не в статическую библиотеку.

Я знаю, что это не правильный метод, но он работает пока.

Это может быть проблема с OS 3.0, так как это было проблемой для Three20.

Ответ 2

К сожалению, из-за того, какие категории работают и динамический характер среды выполнения Objective-C, не все хорошо работает со статическими библиотеками. Причина, по которой вы получаете эту ошибку, заключается в том, что реализация категории в статической библиотеке никогда фактически не связана с исполняемым изображением, потому что компилятор не знает, что код выполнения будет необходим во время выполнения.

Чтобы исправить это, вы можете заставить компоновщик копировать объектные файлы из статического архива для любых и всех Objective-C изображений класса и категории. Недостатком является то, что ваш исполняемый файл будет включать код изображения для классов, которые вы не можете использовать вообще. Чтобы заставить компоновщик включать код категории, добавьте -ObjC в настройку сборки OTHER_LD_FLAGS в Xcode. Теперь реализация вашей категории будет скопирована из статического архива в ваш исполняемый файл, и вы не получите исключение во время выполнения.

Ответ 3

Я только что поговорил с инженером Apple об этом, и это было рассмотрено в ld с версиями > 100. Это включено в XCode4. Он провел меня через это, и я попробовал это сам, и действительно проблема категории исправлена.

Выньте "-all_load" и вернитесь к "-ObjC" в настройках сборки с помощью нового компоновщика.

Ответ 4

Если вы используете Xcode 3.2, вы можете избежать использования -all_load и вместо этого использовать -force_load только для соответствующей библиотеки, что должно быть немного более эффективным.

Это описано в недавно обновленном Apple Technical QA: http://developer.apple.com/mac/library/qa/qa2006/qa1490.html

Ответ 5

Вопрос о том, что флаги компоновщика -all_load или -force_load были необходимы для привязки категорий, были исправлены в LLVM. Исправляемые корабли как часть LLVM 2.9. Первая версия Xcode, которая содержит исправление, - это Xcode 4.2, отправляемая с LLVM 3.0. Указанные исправления больше не нужны при работе с Xcode 4.2. Флаг -ObjC по-прежнему необходим при связывании двоичных файлов ObjC

Ответ 6

Недавно я столкнулся с этой проблемой. Мне не удалось заставить -all_load работать, когда я заметил, что другая категория, в которой я работал DID. Я был ленив для этой категории и включил ее в другой файл.

В итоге я создал фиктивный класс (без методов, переменные экземпляра) и включил реализацию моих категорий в файл .m для этого фиктивного класса. После этого мои категории начали работать даже после того, как я удалил флаг -all_load.

Это было на iPhone OS 3.1.3.

Это, конечно, не правильный способ его исправления, но, похоже, он работает.

Полный образец кода находится на моем blog для моих (тривиальных) категорий.

Ответ 7

У меня была такая же проблема, но добавление какой-либо комбинации описанных флагов (-ObjC, -all_load, -force_load) не сработало.

Оказалось, что при добавлении файлов в проект я не установил флажок "Добавить в цель". Я удалил файлы из проекта и добавил их снова, на этот раз убедившись, что это окно было проверено. Это устранило проблему.

Ответ 8

В прошлом мне удалось принудительно связать категорию с -u.objc_category_name_UIView_Extensions, но с отключенной средой 3.0 dev, и единственным вариантом является -all_load.

Ответ 9

У меня была такая же проблема со статьями в моей статической библиотеке. В моем случае "-all_load" не помогло, так как вызвало множество ошибок сборки (моя статическая библиотека является оберткой вокруг другой частной C/С++ lib).

Я решил это с помощью взлома, предложенного http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html, который просто включал добавление определения типа пустого (пустого) в файлы категорий. Используя этот хак, я сохранил "-ObjC", но сбросил "-all_load" в настройках компоновщика приложения, и он отлично работал на устройстве.