Вызов метода для категории, включенной в статическую библиотеку iPhone, вызывает NSInvalidArgumentException

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

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

В этой категории у меня есть метод, который называется:

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

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

Однако, если попытаться запустить приложение на устройстве, я получаю исключение 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, и у меня возникла та же проблема.

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

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

Я проверил проект статической библиотеки, категории включены в целевые группы "copy headers" и "compile sources".

Статическая библиотека входит в группу основных проектов "связать бинарный файл с библиотекой".

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

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

-ObjC флаг компоновщика установлен

Есть идеи?


нм выход

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

9 ответов

Решение

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

"-All_load"

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

РЕДАКТИРОВАТЬ: Обязательно добавьте этот флаг в проект, включая статическую библиотеку, а не в саму статическую библиотеку.

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

Возможно, это проблема ОС 3.0, так как это было обходным решением для Three20.

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

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

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

Удалите "-all_load" и вернитесь к "-ObjC" в настройках сборки с новым компоновщиком.

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

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

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

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

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

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

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

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

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

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

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

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

Раньше мне удавалось принудительно связать категорию с помощью -u .objc_category_name_UIView_Extensions, но в среде разработчика 3.0 это не работает, и единственным вариантом кажется -all_load.

Другие вопросы по тегам