Можно ли вести меня, как правильно связать статическую библиотеку с проектом iPhone. Я использую статический проект библиотеки, добавленный к проекту приложения как прямая зависимость (цель-> общий-> прямые зависимости) и все работы хорошо, но категории. Категория, определенная в статической библиотеке, не работает в приложении.
Таким образом, мой вопрос состоит в том, как добавить статическую библиотеку с некоторыми категориями в другой проект?
И в целом, что лучшая практика должна использовать в коде проекта приложения из других проектов?
Решение: Начиная с версии Xcode 4.2, вам нужно перейти к приложению, которое связывается с библиотекой (не к самой библиотеке), щелкнуть проект в Project Navigator, выбрать цель приложения, затем build settings, затем найти "Other Linker Flags", нажать кнопку + и добавить '-ObjC'. '-all_load' и '-force_load' больше не нужны.
Details: Я нашел несколько ответов на различных форумах, блогах и в документах apple. Сейчас я попытаюсь сделать краткое резюме моих поисков и экспериментов.
Проблема была вызвана (цитата из apple Technical Q&A QA1490 https://developer.apple.com/library/content/qa/qa1490/_index.html):
Objective-C не определяет линкерные символы для каждой функции (или метода, в Objective-C) - вместо этого символы компоновщика символы генерируются только для каждого класса. Если вы расширяете уже существующий класс с помощью категорий, компоновщик не знает, как связать объектный код реализации основного класса и реализации категории. Это не позволяет объектам, созданным в результирующем приложении, не могут реагировать на селектор, который определен в категории.
И их решение:
Чтобы решить эту проблему, статическая библиотека должна передавать опцию -ObjC компоновщику. Этот флаг заставляет компоновщик загружать каждый объектный файл в библиотеки, который определяет Objective-C класс или категорию. Хотя эта опция обычно приводит к более крупный исполняемый файл (из-за дополнительного объектного кода, загружаемого в приложение), он позволит успешное создание эффективных статических библиотек Objective-C, которые содержат категории на существующих классы.
и также есть рекомендация в iPhone Development FAQ:
Как связать все классы Objective-C классы в статической библиотеке? Установите параметр Other Linker Flags build setting в значение -ObjC.
и описания флагов:
-all_load Загружает все члены статических архивных библиотек.
-ObjC Загружает все члены статических архивных библиотек, которые реализуют класс или категорию Objective-C. Objective-C класс или категорию.
-force_load (path_to_archive) Загружает все члены указанной статической архивной библиотеки. архивной библиотеки. Примечание: -all_load заставляет все члены всех архивов быть загружены. Эта опция позволяет вам выбрать конкретный архив.
* Мы можем использовать force_load для уменьшения размера двоичного файла приложения и для избежания конфликтов, которые может вызвать all_load в некоторых случаях.
Да, это работает с файлами *.a, добавленными в проект. Однако у меня возникли проблемы с проектом lib, добавленным в качестве прямой зависимости. Но позже я обнаружил, что это была моя ошибка - возможно, проект прямой зависимости был добавлен неправильно. Когда я удаляю его и добавляю снова, я делаю следующие шаги:
после этого все работает нормально. Флага "-ObjC" в моем случае было достаточно.
Меня также заинтересовала идея из блога http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html. Автор говорит, что он может использовать категории из lib без установки флага -all_load или -ObjC. Он просто добавляет в h/m файлы категории пустой фиктивный класс интерфейса/реализации, чтобы заставить компоновщик использовать этот файл. И да, этот трюк сработал.
Но автор также сказал, что он даже не инстанцировал фиктивный объект. Мм... Как я обнаружил, мы должны явно вызывать некоторый "реальный" код из файла категории. Так что, по крайней мере, функция класса должна быть вызвана. И нам даже не нужен фиктивный класс. Одиночная функция c делает то же самое.
Так что если мы напишем lib файлы как:
// mylib.h
void useMyLib();
@interface NSObject (Logger)
-(void)logSelf;
@end
// mylib.m
void useMyLib(){
NSLog(@"do nothing, just for make mylib linked");
}
@implementation NSObject (Logger)
-(void)logSelf{
NSLog(@"self is:%@", [self description]);
}
@end
и если мы вызовем useMyLib(); в любом месте проекта App то в любом классе мы можем использовать метод категории logSelf;
[self logSelf];
И еще блоги по теме:
http://t-machine.org/index.php/2009/10/13/how-to-make-an-iphone-static-library-part-1/
http://blog.costan.us/2009/12/fat-iphone-static-libraries-device-and.html
Вам, вероятно, понадобится категория в заголовке "public" статической библиотеки: #import "MyStaticLib.h"
{{ 1}}