Слабая ссылка iOS Framework: ошибка неопределенных символов

Я создаю свой собственный фреймворк, который предлагается распространять среди других разработчиков для включения в их проекты. Этот фреймворк опционально связывает определенные фреймворки (например, CoreLocation). Проблема заключается в том, что когда я связываю свою инфраструктуру с реальным автономным проектом, который не содержит CoreLocation в фазах сборки, я получаю ошибки компоновщика, такие как "неопределенные символы для архитектуры", когда пытаюсь построить этот хост-проект

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_CLLocationManager", referenced from:
      objc-class-ref in MySDK(MyServerConnection.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Можно ли избежать этого, потому что я не хочу заставлять разработчиков включать CoreLocation в свои проекты? На самом деле, я знаю, что это возможно, но что я должен сделать, чтобы добиться этого?

2 ответа

Решение

Из описания вашей проблемы я предполагаю, что вы уже знаете, как сделать Xcode слабой связью со структурой, установив его как "Необязательный".

Вам нужно решить две проблемы: наличие класса и наличие символа. Apple рассматривает это в Руководстве по программированию на платформе Framework: слабые связи и фреймворки и в Руководстве по совместимости с SDK: Использование разработки на основе SDK

Наличие класса

Это довольно просто: используйте NSClassFromString() чтобы увидеть, доступен ли класс в текущей среде.

if (NSClassFromString("CLLocationManager") != NULL){

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

Наличие символа

Что вас особенно интересует, так это использование констант или структур из слабо связанных структур. Функция в стиле C была бы похожа, но это не проблема при использовании CoreLocation. Мы будем использовать константу CoreLocation в качестве примера.

Каждый раз, когда вы используете его, вы ДОЛЖНЫ проверить, чтобы убедиться, что он существует:

if (&kCLErrorDomain != NULL){
   // Use the constant
}

Обратите внимание, что & принимает адрес константы для сравнения. Также обратите внимание, что вы НЕ МОЖЕТЕ сделать это:

if (kCLErrorDomain){
   // Use the constant
}

Или это:

if (&kCLErrorDomain){
   // Use the constant
}

Постоянные символы также можно искать во время выполнения с помощью dlsym. Использование оператора отрицания таким способом не будет работать. Вы должны проверить адрес константы по нулевому адресу.

Я привел очень простой пример приложения, использующего статическую библиотеку, которая содержит слабые ссылки на Core Location на GitHub. Пример приложения не связывается с Базовым местоположением:

TestApp

Но зависимость делает, как необязательный (слабый) каркас:

необязательный каркас

Вы можете обернуть любой код и импортировать, которые используют каркас CoreLocation в

#ifdef __CORELOCATION__
... do stuff
#endif

Это сведет на нет весь код CoreLocation, когда инфраструктура не связана во время компиляции

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