Каковы распространенные случаи использования __IPHONE_OS_VERSION_MAX_ALLOWED?

В каких ситуациях вы бы использовали проверку __IPHONE_OS_VERSION_MAX_ALLOWED? А как насчет __IPHONE_OS_VERSION_MIN_REQUIRED?

2 ответа

Решение

Важно понимать, что это константы времени компиляции, поэтому они бесполезны для определения во время выполнения, на какой платформе или версии ОС вы работаете (например, для определения, работаете ли вы на iPad или iPhone).

Эти константы позволяют вам определять во время компиляции, создается ли код для данного SDK или цели развертывания. Например, если вы написали библиотеку с открытым исходным кодом, которая содержит код, который работает только при компиляции с iOS 5 SDK, вы можете включить эту проверку, чтобы определить, для какого SDK компилируется код:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000
    //you can use iOS 5 APIs here because the SDK supports them
    //but the code may still crash if run on an iOS 4 device
#else
    //this code can't use iOS 5 APIs as the SDK version doesn't support them
#endif

Или, в качестве альтернативы, если вы хотите узнать, какая минимальная версия ОС предназначена для...

#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
    //minimum deployment target is 5.0, so it's safe to use iOS 5-only code
#else
    //you can use iOS5 APIs, but the code will need to be backwards
    //compatible or it will crash when run on an iOS 4 device
#endif

Это отличается от определения во время выполнения, на какой ОС вы работаете. Если вы скомпилируете код в первом примере выше с помощью iOS 4 SDK, он будет использовать ваш безопасный код iOS 4, но не будет использовать какие-либо функции iOS 5 при запуске на устройстве iOS 5. Если вы создадите его с помощью iOS 5 SDK, а затем установите целевое значение для развертывания iOS 4 и попытаетесь запустить его на устройстве iOS 4, оно будет хорошо скомпилировано и установлено, но все равно может произойти сбой во время выполнения, поскольку API-интерфейсы iOS 5 отсутствуют.

Во втором приведенном выше примере, если вы установите цель развертывания на iOS 4 или ниже, он будет использовать безопасный путь к коду iOS 4, но если вы установите цель развертывания на iOS 5, он вообще не будет работать на iOS 4 устройства (оно откажется от установки).

Чтобы создать приложение, работающее на iOS 4 и 5 и все еще способное использовать функции iOS 5, если они доступны, вам необходимо определить время выполнения. Чтобы определить версию iOS во время выполнения, вы можете сделать это:

if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0.1" options:NSNumericSearch] != NSOrderedAscending) {
    //running on iOS 5.0.1 or higher
}

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

if ([SomeClass class]) {
    //this class exists
}

if ([SomeClass instancesRespondToSelector:@selector(someMethod:)]) {
    //this method exists
}

Кроме того, чтобы обнаружить во время выполнения, если вы находитесь на iPad или iPhone, вы можете сделать это:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    //on an ipad
}

Выполнение этих проверок во время выполнения позволяет вам создать единое приложение, которое работает на нескольких устройствах и версиях iOS и способно использовать преимущества каждой платформы.

Практическая реализация / пример использования instancesRespondToSelector:, расширяющий anwser @Nick Lockwood:

+(BOOL) testIsHeaderInConnectData:(NSData *) connectData {
    static NSString *headString = nil;
    static NSData *headData = nil;
    static BOOL rangeCheckOk = NO;
    static BOOL rangeCheckTestComplete = NO;
    if (!rangeCheckTestComplete) {
        rangeCheckOk = [NSData instancesRespondToSelector:@selector(rangeOfData:options:range:)]; 
        headString = @"HEAD ";
        headData = (rangeCheckOk?[[NSData alloc] initWithBytes:headString.UTF8String length:headString.length]:nil);
        headString = (rangeCheckOk?nil:[[NSString alloc ]initWithString:headString]);
        rangeCheckTestComplete = YES;
    }

    NSInteger testLength = connectData.length;
    BOOL isHeader = testLength > 5;
    if (isHeader) {
        testLength = (testLength < 128?testLength:128);
        if (rangeCheckOk) {
             isHeader = [connectData rangeOfData:headData options:0 range:(NSRange){0,testLength}].location!=NSNotFound;
        } else {
            NSString *headStart = [[NSString alloc] initWithBytes:connectData.bytes length:testLength encoding:NSUTF8StringEncoding];
            isHeader = [headStart rangeOfString:headString].location!=NSNotFound;
            [headStart release];
        }
    }
    return isHeader;
}
Другие вопросы по тегам