Используя основанную на SDK разработку
В этой главе описываются основанные на SDK методы разработки для использования в проектах XCode, объясняя, как Вы можете:
Использование слабо соединило классы, методы и функции для поддержки работы многократных версий операционной системы
Ссылка Weakly вся платформа
Скомпилируйте условно для различного SDKs
Найдите использование осуждаемого APIs в Вашем коде
Определите версию операционной системы или версию платформы, во время выполнения
Для фона на слабом соединении считайте Слабое Соединение и Платформы Apple.
Используя Слабо Соединенные Классы в iOS
Если Ваш проект XCode использует слабо соединенные классы, необходимо гарантировать доступность тех классов во время выполнения перед использованием их. Попытка использовать недоступный класс может генерировать ошибку привязки во время выполнения от динамического компоновщика, который может завершить соответствующий процесс.
Проекты XCode, которые используют основной SDK iOS 4.2 или позже должны использовать NSObject
class
метод для проверения наличия слабо соединенных классов во время выполнения. Этот простой, эффективный механизм использует в своих интересах NS_CLASS_AVAILABLE
макрос доступности класса, доступный для большинства платформ в iOS.
Для платформ iOS, поддерживающих NS_CLASS_AVAILABLE
макрос, conditionalize Ваш код для слабо соединенных классов, как продемонстрировано в следующем примере:
if ([UIPrintInteractionController class]) { |
// Create an instance of the class and use it. |
} else { |
// Alternate code path to follow when the |
// class is not available. |
} |
Это работает, потому что, если слабо соединенный класс не доступен, отправляя сообщение в него, походит на отправку сообщения к nil
. Если Вы разделяете слабо соединенный класс на подклассы, и суперкласс недоступен, то подкласс также кажется недоступным.
Использовать class
метод как показано здесь, необходимо сделать больше, чем гарантируют что поддержка платформы NS_CLASS_AVAILABLE
макрос. Необходимо также сконфигурировать определенные настройки проекта. С этими требуемыми настройками на месте, предыдущий код безопасно тестирует доступность класса, работая на версии iOS, в котором не присутствует класс. Эти настройки следующие:
Основной SDK для Вашего проекта XCode должен быть iOS 4.2 или более новый. Имя для этой установки в редакторе настроек сборки
SDKROOT (Base SDK)
.Цель развертывания для Вашего проекта должна быть iOS 3.1 или более новый. Имя для этой установки
MACOSX_DEPLOYMENT_TARGET (OS X Deployment Target)
.Компилятор для Вашего проекта должен быть компилятором LLVM-GCC 4.2 или более новый, или компилятором LLVM (Лязг) 1.5 или более новый. Имя для этой установки
GCC_VERSION (C/C++ Compiler Version)
.Необходимо гарантировать, что любые платформы, не доступные в цели развертывания проекта, слабо соединяются, а не требуются. Посмотрите Слабое Соединение со Всей Платформой и Соединение Библиотек и Платформ в Руководстве по управлению проектами XCode.
Для получения информации об использовании редактора настроек сборки XCode посмотрите Строительные изделия в Руководстве по управлению проектами XCode.
В OS X (и в проектах iOS, не встречающих набор условий, просто перечисленных), Вы не можете использовать class
метод, чтобы определить, доступен ли слабо соединенный класс. Вместо этого используйте NSClassFromString
функция в коде, подобном следующему:
Class cls = NSClassFromString (@"NSRegularExpression"); |
if (cls) { |
// Create an instance of the class and use it. |
} else { |
// Alternate code path to follow when the |
// class is not available. |
} |
Используя слабо соединенные методы, функции и символы
Если Ваш проект использует слабо соединенные методы, функции или внешние символы, необходимо гарантировать их доступность во время выполнения перед использованием их. При попытке использовать недоступный элемент, динамический компоновщик может генерировать ошибку привязки во время выполнения и завершить соответствующий процесс.
Предположим, что Вы устанавливаете основной SDK в своем проекте XCode к iOS 4.0. Это позволяет Вашему коду использовать функции в той версии операционной системы при выполнении в той версии. Предположим также, что Вы хотите, чтобы Ваше программное обеспечение работало в iOS 3.1, даже при том, что это не может использовать более новые функции в той версии OS. Позвольте это, ставя цель развертывания к более ранней версии операционной системы.
В Objective C, instancesRespondToSelector:
если данный селектор метода доступен, метод говорит Вам. Например, для использования availableCaptureModesForCameraDevice:
метод, сначала доступный в iOS 4.0, Вы могли использовать код как следующее:
Перечисление 3-1 , Проверяющее наличие метода Objective C
if ([UIImagePickerController instancesRespondToSelector: |
@selector (availableCaptureModesForCameraDevice:)]) { |
// Method is available for use. |
// Your code can check if video capture is available and, |
// if it is, offer that option. |
} else { |
// Method is not available. |
// Alternate code to use only still image capture. |
} |
Когда Ваш код работает в iOS 4.0 или позже, это может вызвать availableCaptureModesForCameraDevice:
определить, доступна ли видеосъемка на устройстве. Когда это работает в iOS 3.1, однако, это должно предположить, что только получение неподвижного изображения доступно.
Если бы необходимо было создать этот код с различными настройками, Вы видели бы следующие результаты:
Если Вы указываете основную установку SDK
iphoneos3.1
:Сборка перестала бы работать потому что
availableCaptureModesForCameraDevice:
метод не определяется в той версии системы.Если Вы указываете основную установку SDK
iphoneos4.0
, и затем поставленный цель развертывания к:iphoneos4.0
: Программное обеспечение работало бы только в iOS 4.0 или позже и не запустится в более ранних системах.iphoneos3.1
: Программное обеспечение работало бы в iOS 4.0 и в iOS 3.1, но не запустится в более ранних системах. При выполнении в iOS 3.1 программное обеспечение использовало бы альтернативный код для получения изображений.
Проверьте наличие свойства Objective-C путем передачи имени метода получателя (который совпадает с именем свойства) к instancesRespondToSelector:
.
Чтобы определить, доступна ли слабо соединенная функция C, используйте факт, что компоновщик устанавливает адрес недоступных функций к NULL
. Проверьте адрес функции — и следовательно, его доступность — путем сравнения адреса с NULL
или nil
. Например, перед использованием CGColorCreateGenericCMYK
функция в проекте, цель развертывания которого ранее, чем OS X v10.5, используйте код как следующее:
Перечисление 3-2 , Проверяющее наличие функции C
if (CGColorCreateGenericCMYK != NULL) { |
CGColorCreateGenericCMYK (0.1,0.5.0.0,1.0,0.1); |
} else { |
// Function is not available. |
// Alternate code to create a color object with earlier technology |
} |
Проверьте наличие внешнего (extern
) постоянный или уведомление называют путем явного сравнения его адреса — а не пустого имени символа — к NULL
или nil
.
Слабое соединение со всей платформой
Если Вы используете недавно добавленную платформу — та, ставшая доступной после Вашей цели развертывания — Вы должны явно слабая ссылка к самой платформе. Например, скажите, что Вы хотите соединиться с Ускорять платформой, сначала доступной в iOS 4.0, использовать его функции в системах, в которых они доступны. Кроме того, скажите, что Вы ставите свою цель развертывания к iOS 3.1.3, позволяя пользователям той версии iOS использовать Ваше приложение без новых функций. В этом примере Вы должны слабая ссылка к Ускорять платформе.
При использовании платформы, которая доступна в Вашей цели развертывания, необходимо потребовать, что платформа (и не слабо соединяют его).
Для получения информации о том, как слабо соединиться с платформой, обратитесь к Соединению Библиотек и Платформ в Руководстве по управлению проектами XCode.
Условно компилируя для различного SDKs
При использовании одного набора исходного кода для создания больше чем для одного основного SDK, Вам, возможно, понадобилось бы к conditionalize для основного SDK в использовании. Сделайте это при помощи директив препроцессору с макросами, определенными в Availability.h
.
Предположим, что Вы хотите скомпилировать код, показанный в Перечислении 3-2 с помощью основной установки SDK macosx10.4
. Часть кода, относящегося к CGColorCreateGenericCMYK
функция — представленный в OS X v10.5 — должна быть замаскирована во время сборки. Это вызвано тем, что любая ссылка на недоступное CGColorCreateGenericCMYK
функция вызвала бы ошибку компилятора.
Чтобы позволить коду создавать, используйте __MAC_OS_X_VERSION_MAX_ALLOWED
макрос к:
Гарантируйте, что цель проекта является OS X и не iOS
Скройте код, который недоступен в основном SDK
Следующая выборка кода демонстрирует это. Заметьте использование численного значения 1050
вместо символа __MAC_10_5
в #if
пункт сравнения: Если код загружается в более старой системе, не включающей определение символа, сравнение все еще работает.
Перечисление 3-3 Используя директивы препроцессору для условной компиляции
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED |
// code only compiled when targeting OS X and not iOS |
// note use of 1050 instead of __MAC_10_5 |
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 |
if (CGColorCreateGenericCMYK != NULL) { |
CGColorCreateGenericCMYK(0.1,0.5.0.0,1.0,0.1); |
} else { |
#endif |
// code to create a color object with earlier technology |
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 |
} |
#endif |
#endif |
} |
В дополнение к использованию макросов препроцессора предыдущий код также предполагает, что код мог быть скомпилирован с помощью более нового основного SDK, но развернут на компьютере рабочий OS X v10.4 и ранее. В частности это проверяет на существование слабо соединенный CGColorCreateGenericCMYK
символ прежде, чем попытаться вызвать его. Это препятствует тому, чтобы код генерировал ошибку периода выполнения, которая может произойти, если Вы создаете код против более нового SDK, но развертываете его в более старой системе. Для получения дополнительной информации об учреждении проверок на этапе выполнения для определения присутствия символов посмотрите Используя Слабо Соединенные Классы в iOS и Используя Слабо Соединенные Методы и Функции.
Нахождение экземпляров осуждаемого использования API
Поскольку iOS и OS X развиваются, APIs и технологии, которые они охватывают, иногда изменяются для удовлетворения потребностей разработчиков. Как часть этого развития, менее эффективные интерфейсы осуждаются в пользу более новых. Макросы доступности, присоединенные к объявлениям в заголовочных файлах, помогают Вам найти устаревшие (deprecated) интерфейсы. Справочная документация также отмечает устаревшие (deprecated) интерфейсы.
Если Вы компилируете проект с целью развертывания OS X v10.5 и используете интерфейс, тегированный, как осуждается, компилятор выпускает соответствующее предупреждение. Предупреждение включает имя осуждаемого интерфейса и где в Вашем коде это использовалось. Например, если HPurge
функция осуждалась, Вы получите ошибку, подобную следующему:
'HPurge' is deprecated (declared at /Users/steve/MyProject/main.c:51)
Для определения местоположения экземпляров осуждаемого использования API в коде ищите предупреждения этого типа. Если Ваш проект имеет много предупреждений, используйте поле поиска в XCode для фильтрации списка предупреждений на основе «осуждаемого» ключевого слова.
Определение версии операционной системы или платформы
В редких экземплярах, проверяя наличие времени выполнения символа не полное решение. Например, если поведение метода изменилось от одной версии ОС до другого, или если ошибка была исправлена в ранее доступном методе, важно записать Ваш код для принятия во внимание тех изменений.
Метод для использования для проверки версии операционной системы зависит от целевой платформы, следующим образом:
Для проверки версии iOS во время выполнения используйте код как this:.
NSString *osVersion = [[UIDevice currentDevice] systemVersion];
Для проверки версии OS X во время выполнения используйте функцию Гештальта и константы Селекторов Версии системы.
Также для многих платформ, можно проверить версию определенной платформы во время выполнения. Чтобы сделать это, используйте глобальные константы версии платформы — если им предоставлена платформа. Например, Набор Приложения (в NSApplication.h
) объявляет NSAppKitVersionNumber
постоянный, который можно использовать для обнаружения различных версий платформы Набора Приложения:
APPKIT_EXTERN double NSAppKitVersionNumber; |
#define NSAppKitVersionNumber10_0 577 |
#define NSAppKitVersionNumber10_1 620 |
#define NSAppKitVersionNumber10_2 663 |
#define NSAppKitVersionNumber10_2_3 663.6 |
#define NSAppKitVersionNumber10_3 743 |
#define NSAppKitVersionNumber10_3_2 743.14 |
#define NSAppKitVersionNumber10_3_3 743.2 |
#define NSAppKitVersionNumber10_3_5 743.24 |
#define NSAppKitVersionNumber10_3_7 743.33 |
#define NSAppKitVersionNumber10_3_9 743.36 |
#define NSAppKitVersionNumber10_4 824 |
#define NSAppKitVersionNumber10_4_1 824.1 |
#define NSAppKitVersionNumber10_4_3 824.23 |
#define NSAppKitVersionNumber10_4_4 824.33 |
#define NSAppKitVersionNumber10_4_7 824.41 |
#define NSAppKitVersionNumber10_5 949 |
#define NSAppKitVersionNumber10_5_2 949.27 |
#define NSAppKitVersionNumber10_5_3 949.33 |
Можно выдержать сравнение со значением этой константы для определения, против какой версии Набора Приложения код работает. Один типичный подход должен поставить в тупик значение глобальной константы и проверить результат по константам, объявленным в NSApplication.h
. Например:
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_0) { |
/* On a 10.0.x or earlier system */ |
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) { |
/* On a 10.1 - 10.1.x system */ |
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_2) { |
/* On a 10.2 - 10.2.x system */ |
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_3) { |
/* On 10.3 - 10.3.x system */ |
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) { |
/* On a 10.4 - 10.4.x system */ |
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) { |
/* On a 10.5 - 10.5.x system */ |
} else { |
/* 10.6 or later system */ |
} |
Точно так же основа (в NSObjCRuntime.h
) объявляет NSFoundationVersionNumber
глобальные постоянные и определенные значения для каждой версии.
Некоторые отдельные заголовки для других объектов и компонентов могут также объявить номера версий для NSAppKitVersionNumber
где некоторое исправление ошибки или функциональность доступны в данном обновлении.