Слабая ссылка 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. Пример приложения не связывается с Базовым местоположением:
Но зависимость делает, как необязательный (слабый) каркас:
Вы можете обернуть любой код и импортировать, которые используют каркас CoreLocation в
#ifdef __CORELOCATION__
... do stuff
#endif
Это сведет на нет весь код CoreLocation, когда инфраструктура не связана во время компиляции