Как проверить версию iOS? - PullRequest
818 голосов
/ 27 июля 2010

Я хочу проверить, больше ли iOS версия устройства, чем 3.1.3 Я пробовал такие вещи, как:

[[UIDevice currentDevice].systemVersion floatValue]

но это не работает, я просто хочу:

if (version > 3.1.3) { }

Как мне этого добиться?

Ответы [ 36 ]

1 голос
/ 07 октября 2013

В качестве варианта решения yasimturks я определил одну функцию и несколько значений enum вместо пяти макросов.Я нахожу это более элегантным, но это дело вкуса.

Использование:

if (systemVersion(LessThan, @"5.0")) ...

.h файл:

typedef enum {
  LessThan,
  LessOrEqual,
  Equal,
  GreaterOrEqual,
  GreaterThan,
  NotEqual
} Comparison;

BOOL systemVersion(Comparison test, NSString* version);

.m файл:

BOOL systemVersion(Comparison test, NSString* version) {
  NSComparisonResult result = [[[UIDevice currentDevice] systemVersion] compare: version options: NSNumericSearch];
  switch (test) {
    case LessThan:       return result == NSOrderedAscending;
    case LessOrEqual:    return result != NSOrderedDescending;
    case Equal:          return result == NSOrderedSame;
    case GreaterOrEqual: return result != NSOrderedAscending;
    case GreaterThan:    return result == NSOrderedDescending;
    case NotEqual:       return result != NSOrderedSame;
  }
}

Вы должны добавить префикс вашего приложения к именам, особенно к типу Comparison.

1 голос
/ 02 октября 2014

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

- (BOOL) isIOS8OrAbove{
    float version802 = 1140.109985;
    float version8= 1139.100000; // there is no def like NSFoundationVersionNumber_iOS_7_1 for ios 8 yet?
    NSLog(@"la version actual es [%f]", NSFoundationVersionNumber);
    if (NSFoundationVersionNumber >= version8){
        return true;
    }
    return false;
}
1 голос
/ 18 сентября 2014

Я знаю, что это старый вопрос, но кто-то должен был упомянуть макросы времени компиляции в Availability.h.Все остальные методы здесь являются решениями времени выполнения и не будут работать в заголовочном файле, категории класса или определении ivar.

Для этих ситуаций используйте

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_6_0
  // iOS 6+ code here
#else
  // Pre iOS 6 code here
#endif

ч / т этот ответ

1 голос
/ 30 мая 2015
#define IsIOS8 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)
1 голос
/ 19 марта 2015

Решение для проверки версии iOS в Swift

switch (UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch)) {
    case .OrderedAscending:
       println("iOS < 8.0")

    case .OrderedSame, .OrderedDescending:
       println("iOS >= 8.0")
}

Недостаток этого решения: это просто плохая практика - сравнивать номера версий ОС, в зависимости от того, как вы это делаете. Никогда не следует жестко кодировать зависимости таким образом, всегда проверять возможности, возможности или существование класса. Учти это; Apple может выпустить обратно совместимую версию класса, если они это сделают, то предложенный вами код никогда не будет использовать ее, поскольку ваша логика ищет номер версии ОС, а НЕ существование класса.

( Источник этой информации )

Решение для проверки существования класса в Swift

if (objc_getClass("UIAlertController") == nil) {
   // iOS 7
} else {
   // iOS 8+
}

Не используйте if (NSClassFromString("UIAlertController") == nil), потому что он корректно работает на симуляторе iOS с использованием iOS 7.1 и 8.2, но если вы тестируете на реальном устройстве с помощью iOS 7.1, вы, к сожалению, заметите, что никогда не пройдете через остальную часть фрагмент кода.

0 голосов
/ 27 января 2017

Есть несколько проблем с двумя популярными ответами:

  1. Сравнение строк с использованием NSNumericSearch иногда приводит к неинтуитивным результатам (от этого страдают все макросы SYSTEM_VERSION_*):

    [@"10.0" compare:@"10" options:NSNumericSearch] // returns NSOrderedDescending instead of NSOrderedSame
    

    FIX : сначала нормализуйте строки, а затем выполните сравнения. Может быть раздражает попытка получить обе строки в одинаковых форматах.

  2. Использование символов версии базового фреймворка невозможно при проверке будущих версий

    NSFoundationVersionNumber_iOS_6_1 // does not exist in iOS 5 SDK
    

    FIX : выполните два отдельных теста, чтобы убедиться, что символ существует, и ТОГДА сравните символы. Однако другое здесь:

  3. Символы базовых версий каркаса не являются уникальными для версий iOS. Несколько версий iOS могут иметь одну и ту же версию фреймворка.

    9.2 & 9.3 are both 1242.12
    8.3 & 8.4 are both 1144.17
    

    FIX : я считаю, что эта проблема неразрешима


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

Добавлены два других метода для удобного сравнения строк версии iOS и для сравнения строк с произвольным числом компонентов.

+ (SInt64)integerFromVersionString:(NSString *)versionString withComponentCount:(NSUInteger)componentCount
{
    //
    // performs base conversion from a version string to a decimal value. the version string is interpreted as
    // a base-10000 number, where each component is an individual digit. this makes it simple to use integer
    // operations for comparing versions. for example (with componentCount = 4):
    //
    //   version "5.9.22.1" = 5*1000^3 + 9*1000^2 + 22*1000^1 + 1*1000^0 = 5000900220001
    //    and
    //   version "6.0.0.0" = 6*1000^3 + 0*1000^2 + 0*1000^1 + 0*1000^1 = 6000000000000
    //    and
    //   version "6" = 6*1000^3 + 0*1000^2 + 0*1000^1 + 0*1000^1 = 6000000000000
    //
    // then the integer comparisons hold true as you would expect:
    //
    //   "5.9.22.1" < "6.0.0.0" // true
    //   "6.0.0.0" == "6"       // true
    //

    static NSCharacterSet *nonDecimalDigitCharacter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,
        ^{  // don't allocate this charset every time the function is called
            nonDecimalDigitCharacter = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
        });

    SInt64 base    = 10000; // each component in the version string must be less than base
    SInt64 result  =     0;
    SInt64 power   =     0;

    // construct the decimal value left-to-right from the version string
    for (NSString *component in [versionString componentsSeparatedByString:@"."])
    {
        if (NSNotFound != [component rangeOfCharacterFromSet:nonDecimalDigitCharacter].location)
        {
            // one of the version components is not an integer, so bail out
            result = -1;
            break;
        }
        result += [component longLongValue] * (long long)pow((double)base, (double)(componentCount - ++power));
    }

    return result;
}

+ (SInt64)integerFromVersionString:(NSString *)versionString
{
    return [[self class] integerFromVersionString:versionString
                               withComponentCount:[[versionString componentsSeparatedByString:@"."] count]];
}

+ (SInt64)integerFromiOSVersionString:(NSString *)versionString
{
    // iOS uses 3-component version string
    return [[self class] integerFromVersionString:versionString
                               withComponentCount:3];
}

Это несколько ориентировано на будущее, поскольку оно поддерживает множество идентификаторов ревизий (через 4 цифры, 0-9999; измените base, чтобы отрегулировать этот диапазон) и может поддерживать произвольное количество компонентов (на данный момент Apple использует 3 компонента Например, major.minor.patch), но это можно указать явно, используя аргумент componentCount. Убедитесь, что ваши componentCount и base не вызывают переполнения, т. Е. Убедитесь, что 2^63 >= base^componentCount!

Пример использования:

NSString *currentVersion = [[UIDevice currentDevice] systemVersion];
if ([Util integerFromiOSVersionString:currentVersion] >= [Util integerFromiOSVersionString:@"42"])
{
    NSLog(@"we are in some horrible distant future where iOS still exists");
}
0 голосов
/ 20 января 2016

Вот Swift-версия макросов yasirmturk.Надеюсь, что это помогает некоторым народам

// MARK: System versionning

func SYSTEM_VERSION_EQUAL_TO(v: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
}

func SYSTEM_VERSION_GREATER_THAN(v: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
}

func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
}

func SYSTEM_VERSION_LESS_THAN(v: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
}

func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
}

let kIsIOS7: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("7")
let kIsIOS7_1: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("7.1")
let kIsIOS8: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("8")
let kIsIOS9: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("9")
0 голосов
/ 17 октября 2013

Все ответы выглядят немного большими. Я просто использую:

if (SYSTEM_VERSION_GREATER_THAN(@"7.0")){(..CODE...)}
if (SYSTEM_VERSION_EQUAL_TO(@"7.0")){(..CODE...)}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")){(..CODE...)}
if (SYSTEM_VERSION_LESS_THAN(@"7.0")){(..CODE...)}
if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@"7.0")){(..CODE...)}

Конечно, замените @"7.0" на требуемую версию ОС.

0 голосов
/ 30 ноября 2012

Более общая версия в Obj-C ++ 11 (возможно, вы могли бы заменить некоторые из этих функций функциями NSString / C, но это менее многословно. Это дает вам два механизма. SplitSystemVersion дает вам массив всех частей, которые полезно, если вы просто хотите включить основную версию (например, switch([self splitSystemVersion][0]) {case 4: break; case 5: break; }).

#include <boost/lexical_cast.hpp>

- (std::vector<int>) splitSystemVersion {
    std::string version = [[[UIDevice currentDevice] systemVersion] UTF8String];
    std::vector<int> versions;
    auto i = version.begin();

    while (i != version.end()) {
        auto nextIllegalChar = std::find_if(i, version.end(), [] (char c) -> bool { return !isdigit(c); } );
        std::string versionPart(i, nextIllegalChar);
        i = std::find_if(nextIllegalChar, version.end(), isdigit);

        versions.push_back(boost::lexical_cast<int>(versionPart));
    }

    return versions;
}

/** Losslessly parse system version into a number
 * @return <0>: the version as a number,
 * @return <1>: how many numeric parts went into the composed number. e.g.
 * X.Y.Z = 3.  You need this to know how to compare again <0>
 */
- (std::tuple<int, int>) parseSystemVersion {
    std::string version = [[[UIDevice currentDevice] systemVersion] UTF8String];
    int versionAsNumber = 0;
    int nParts = 0;

    auto i = version.begin();
    while (i != version.end()) {
        auto nextIllegalChar = std::find_if(i, version.end(), [] (char c) -> bool { return !isdigit(c); } );
        std::string versionPart(i, nextIllegalChar);
        i = std::find_if(nextIllegalChar, version.end(), isdigit);

        int part = (boost::lexical_cast<int>(versionPart));
        versionAsNumber = versionAsNumber * 100 + part;
        nParts ++;
    }

    return {versionAsNumber, nParts};
}


/** Assume that the system version will not go beyond X.Y.Z.W format.
 * @return The version string.
 */
- (int) parseSystemVersionAlt {
    std::string version = [[[UIDevice currentDevice] systemVersion] UTF8String];
    int versionAsNumber = 0;
    int nParts = 0;

    auto i = version.begin();
    while (i != version.end() && nParts < 4) {
        auto nextIllegalChar = std::find_if(i, version.end(), [] (char c) -> bool { return !isdigit(c); } );
        std::string versionPart(i, nextIllegalChar);
        i = std::find_if(nextIllegalChar, version.end(), isdigit);

        int part = (boost::lexical_cast<int>(versionPart));
        versionAsNumber = versionAsNumber * 100 + part;
        nParts ++;
    }

    // don't forget to pad as systemVersion may have less parts (i.e. X.Y).
    for (; nParts < 4; nParts++) {
        versionAsNumber *= 100;
    }

    return versionAsNumber;
}
0 голосов
/ 23 июля 2015

Вот быстрая версия:

struct iOSVersion {
    static let SYS_VERSION_FLOAT = (UIDevice.currentDevice().systemVersion as NSString).floatValue
    static let iOS7 = (Version.SYS_VERSION_FLOAT < 8.0 && Version.SYS_VERSION_FLOAT >= 7.0)
    static let iOS8 = (Version.SYS_VERSION_FLOAT >= 8.0 && Version.SYS_VERSION_FLOAT < 9.0)
    static let iOS9 = (Version.SYS_VERSION_FLOAT >= 9.0 && Version.SYS_VERSION_FLOAT < 10.0)
}

Использование:

if iOSVersion.iOS8 {
    //Do iOS8 code here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...