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