Категории Objective C в статической библиотеке

Можно ли вести меня, как правильно связать статическую библиотеку с проектом iPhone. Я использую статический проект библиотеки, добавленный к проекту приложения как прямая зависимость (цель-> общий-> прямые зависимости) и все работы хорошо, но категории. Категория, определенная в статической библиотеке, не работает в приложении.

Таким образом, мой вопрос состоит в том, как добавить статическую библиотеку с некоторыми категориями в другой проект?

И в целом, что лучшая практика должна использовать в коде проекта приложения из других проектов?

148
задан ThomasW 10 February 2016 в 01:13
поделиться

2 ответа

Решение: Начиная с версии 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, добавленным в качестве прямой зависимости. Но позже я обнаружил, что это была моя ошибка - возможно, проект прямой зависимости был добавлен неправильно. Когда я удаляю его и добавляю снова, я делаю следующие шаги:

  1. Перетаскиваю файл lib project в проект приложения (или добавляю его с помощью Project->Add to project...).
  2. Нажмите на стрелку на иконке проекта lib - появится имя файла mylib.a, перетащите этот файл mylib.a и бросьте его в группу Target -> Link Binary With Library.
  3. Откройте информацию о цели на странице кулака (General) и добавьте мою библиотеку в список зависимостей

после этого все работает нормально. Флага "-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

224
ответ дан 23 November 2019 в 22:28
поделиться

Вам, вероятно, понадобится категория в заголовке "public" статической библиотеки: #import "MyStaticLib.h"

{{ 1}}
-1
ответ дан 23 November 2019 в 22:28
поделиться