Используя основанную на SDK разработку

В этой главе описываются основанные на SDK методы разработки для использования в проектах XCode, объясняя, как Вы можете:

Для фона на слабом соединении считайте Слабое Соединение и Платформы 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, в котором не присутствует класс. Эти настройки следующие:

Для получения информации об использовании редактора настроек сборки 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, однако, это должно предположить, что только получение неподвижного изображения доступно.

Если бы необходимо было создать этот код с различными настройками, Вы видели бы следующие результаты:

Проверьте наличие свойства 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 макрос к:

Следующая выборка кода демонстрирует это. Заметьте использование численного значения 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 для фильтрации списка предупреждений на основе «осуждаемого» ключевого слова.

Определение версии операционной системы или платформы

В редких экземплярах, проверяя наличие времени выполнения символа не полное решение. Например, если поведение метода изменилось от одной версии ОС до другого, или если ошибка была исправлена в ранее доступном методе, важно записать Ваш код для принятия во внимание тех изменений.

Метод для использования для проверки версии операционной системы зависит от целевой платформы, следующим образом:

Также для многих платформ, можно проверить версию определенной платформы во время выполнения. Чтобы сделать это, используйте глобальные константы версии платформы — если им предоставлена платформа. Например, Набор Приложения (в 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 где некоторое исправление ошибки или функциональность доступны в данном обновлении.