จะตรวจสอบเวอร์ชั่น iOS ได้อย่างไร?


848

ฉันต้องการตรวจสอบว่าiOSรุ่นของอุปกรณ์มากกว่าที่3.1.3 ฉันลองทำหรือไม่เช่น:

[[UIDevice currentDevice].systemVersion floatValue]

แต่มันใช้งานไม่ได้ฉันแค่ต้องการ:

if (version > 3.1.3) { }

ฉันจะบรรลุสิ่งนี้ได้อย่างไร


5
ผู้ดำเนินรายการหมายเหตุ : เมื่อเวลาผ่านไปคำถามนี้มีจำนวนมากกว่า 30 คำตอบ ก่อนเพิ่มคำตอบใหม่ตรวจสอบให้แน่ใจว่าโซลูชันของคุณยังไม่ได้ให้บริการ
Matt

3
เริ่มต้น Xcode 7 if #available(iOS 9, *) {}ใน Swift เริ่มต้น Xcode 9 if (@available(iOS 11, *)) {}ใน object-c
Cœur

คำตอบ:


1002

คำตอบด่วน ...


ตั้งแต่ Swift 2.0 คุณสามารถใช้#availableในifหรือguardเพื่อป้องกันโค้ดที่ควรรันในระบบบางระบบเท่านั้น

if #available(iOS 9, *) {}


ใน Objective-C คุณต้องตรวจสอบเวอร์ชั่นของระบบและทำการเปรียบเทียบ

[[NSProcessInfo processInfo] operatingSystemVersion] ใน iOS 8 ขึ้นไป

จาก Xcode 9:

if (@available(iOS 9, *)) {}


คำตอบทั้งหมด ...

ใน Objective-C และ Swift ในบางกรณีจะเป็นการดีกว่าที่จะหลีกเลี่ยงการพึ่งพาเวอร์ชันของระบบปฏิบัติการเพื่อบ่งชี้ถึงความสามารถของอุปกรณ์หรือระบบปฏิบัติการ โดยปกติจะมีวิธีการที่เชื่อถือได้มากขึ้นในการตรวจสอบว่าคุณลักษณะหรือคลาสเฉพาะนั้นพร้อมใช้งาน

ตรวจสอบสถานะของ API:

ตัวอย่างเช่นคุณสามารถตรวจสอบว่าUIPopoverControllerมีอยู่ในอุปกรณ์ปัจจุบันโดยใช้NSClassFromString:

if (NSClassFromString(@"UIPopoverController")) {
    // Do something
}

สำหรับคลาสที่มีการเชื่อมโยงที่ไม่ปลอดภัยจะปลอดภัยในการส่งข้อความถึงคลาสโดยตรง โดยเฉพาะอย่างยิ่งการทำงานนี้สำหรับเฟรมเวิร์กที่ไม่ได้เชื่อมโยงอย่างชัดเจนว่า "จำเป็น" สำหรับคลาสที่หายไปนิพจน์จะประเมินค่าเป็นศูนย์ซึ่งจะทำให้เงื่อนไขล้มเหลว:

if ([LAContext class]) {
    // Do something
}

บางคลาสเช่นCLLocationManagerและUIDeviceให้วิธีการตรวจสอบความสามารถของอุปกรณ์:

if ([CLLocationManager headingAvailable]) {
    // Do something
}

ตรวจสอบการมีสัญลักษณ์:

บางครั้งคุณต้องตรวจสอบว่ามีค่าคงที่หรือไม่ นี้ขึ้นมาใน iOS 8 ด้วยการแนะนำของUIApplicationOpenSettingsURLStringที่ใช้ในการโหลด App -openURL:การตั้งค่าผ่านทาง ค่าที่ไม่มีอยู่ก่อนหน้า iOS 8 การส่งผ่านศูนย์ไปที่ API นี้จะล้มเหลวดังนั้นคุณต้องระมัดระวังในการตรวจสอบการมีอยู่ของค่าคงที่ก่อน:

if (&UIApplicationOpenSettingsURLString != NULL) {
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}

เปรียบเทียบกับรุ่นระบบปฏิบัติการ:

สมมติว่าคุณกำลังเผชิญกับความต้องการที่ค่อนข้างหายากในการตรวจสอบเวอร์ชั่นของระบบปฏิบัติการ สำหรับโครงการที่กำหนดเป้าหมาย iOS 8 ขึ้นไปให้NSProcessInfoรวมวิธีการทำการเปรียบเทียบรุ่นที่มีโอกาสเกิดข้อผิดพลาดน้อยกว่า:

- (BOOL)isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version

โครงการกำหนดเป้าหมายระบบเก่าสามารถใช้บนsystemVersion UIDeviceApple ใช้ในรหัสตัวอย่างGLSprite

// A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer
// class is used as fallback when it isn't available.
NSString *reqSysVer = @"3.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) {
    displayLinkSupported = TRUE;
}

หากด้วยเหตุผลใดก็ตามที่คุณตัดสินใจว่าsystemVersionเป็นสิ่งที่คุณต้องการตรวจสอบให้แน่ใจว่าถือเป็นสตริงหรือคุณเสี่ยงที่จะตัดทอนหมายเลขการแก้ไขแพทช์ (เช่น 3.1.2 -> 3.1)


161
มีบางกรณีที่การตรวจสอบรุ่นของระบบนั้นได้รับการรับประกัน ตัวอย่างเช่นสองคลาสและวิธีการที่เป็นส่วนตัว n 3.x ถูกเผยแพร่สู่สาธารณะใน 4.0 ดังนั้นหากคุณเพียงแค่ตรวจสอบความพร้อมของพวกเขาคุณจะได้รับผลลัพธ์ที่ผิดใน 3.x นอกจากนี้วิธีที่ UIScrollViews จัดการกับมาตราส่วนการซูมเปลี่ยนอย่างละเอียดใน 3.2 และสูงกว่าดังนั้นคุณจะต้องตรวจสอบเวอร์ชั่นของระบบปฏิบัติการเพื่อประมวลผลผลลัพธ์อย่างเหมาะสม
แบรดลาร์สัน

2
iOS 3.2 จะไม่ปรากฏให้ส่งใน-viewWillAppear UISplitViewControllerแฮ็คของฉันคือการตรวจสอบว่า <iOS 4.0 และส่งไปยังตัวควบคุมดูรายละเอียดด้วยตัวเองในรูทวิว-didSelectRowAtIndexPathหรือไม่
jww

10
คุณต้องระวังให้ดีที่นี่เพราะ[@"10.0" compare:@"10" options:NSNumericSearch]ผลตอบแทนNSOrderedDescendingอาจไม่ได้ตั้งใจ (ฉันอาจคาดหวังNSOrderedSame) นี่เป็นความเป็นไปได้ทางทฤษฎีอย่างน้อย
SK9

ใช่ฉันเพิ่งเจอเคสที่ต้องใช้ข้อผิดพลาด iOS 5 เพื่อหลีกเลี่ยง respondsToSelectoret al จะไม่ทำงาน - ต้องเปรียบเทียบเวอร์ชัน
Hot Licks

2
ด้วยการแนะนำ TVos สิ่งนี้ยิ่งทวีความสำคัญมากขึ้น ดูว่า TVos จะส่งคืน 9.0 ในขณะที่ใช้ SDK 9.1 ดังนั้นตรวจสอบคลาสหรือเมธอด (ตัวเลือก) เป็นวิธีที่ดีที่สุดหลังจากนี้คุณควรตรวจสอบNSFoundationVersionNumberและหากไม่สามารถตรวจสอบเวอร์ชั่นของระบบUIDeviceได้
rckoenes

1055
/*
 *  System Versioning Preprocessor Macros
 */ 

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

/*
 *  Usage
 */ 

if (SYSTEM_VERSION_LESS_THAN(@"4.0")) {
    ...
}

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"3.1.1")) {
    ...
}

20
+1 การเก็บสิ่งนี้ไว้ในส่วนหัวที่คุณสามารถรวมได้ในที่ที่จำเป็นคือทางออกที่ง่ายที่สุดที่ฉันสามารถนึกได้ ในหลายกรณีสิ่งนี้มีความน่าเชื่อถือมากกว่าการตรวจสอบความพร้อมใช้งานโดยใช้ NSClassFromString อีกตัวอย่างหนึ่งคือ iAd โดยที่หากคุณใช้ ADBannerContentSizeIdentifierPortrait ในเวอร์ชันก่อน 4.2 คุณจะได้รับ EXEC_BAD_ACCESS แต่ ADBannerContentSizeIdentifier320x50 ที่เทียบเท่าจะถูกคัดค้านหลังจาก 4.1
Rab

1
อีกที่ที่ฉันใช้นี่คือกับ UIPageViewController และตั้งค่าสไตล์เป็น UIPageViewControllerTransitionStyleScroll ใน iOS6
Paul de Lange

7
วิธีนี้ใช้ไม่ได้กับ 10 วินาที ตัวอย่างเช่นการเปรียบเทียบ 4.10 และ 4.9 จะให้ผลลัพธ์ที่ผิด
pzulw

7
ควรใช้ความระมัดระวังเป็นอย่างยิ่งเมื่อใช้.0หมายเลขเสริม ตัวอย่างเช่นSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0.0")ให้ผลลัพธ์ที่ไม่ถูกต้องใน iOS 7.0
Yan

1
ฉันเพิ่งทดสอบการวางไว้ในไฟล์. pch ของฉันและใช้งานได้ดี (การสร้างด้วย Xcode 5 อย่างน้อย)
Whyoz

253

ตามที่แนะนำโดยเอกสาร Apple อย่างเป็นทางการ : คุณสามารถใช้NSFoundationVersionNumber, จากNSObjCRuntime.hไฟล์ส่วนหัว

if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
    // here you go with iOS 7
}

40
+1 นี่คือตัวเลือกที่ปลอดภัยและแม่นยำที่สุดที่นี่
mxcl

8
อืม .. NSFoundationVersionNumber_iOS_6_1ไม่มีอยู่ใน iOS 5 SDK
Kjuly

2
@Kjuly คุณสามารถกำหนดหมายเลขเวอร์ชันที่หายไปได้ด้วยตัวคุณเอง: github.com/carlj/CJAMacros/blob/master/CJAMacros/CJAMacros.h (ดูที่บรรทัด 102-130)
CarlJ

3
ไม่ผิดคุณไม่พบ NSFoundationVersionNumber_iOS_7_0 #ifndef NSFoundationVersionNumber_iOS_7_0 #define NSFoundationVersionNumber_iOS_7_0 1047.00 #endifแต่ดีที่เราสามารถกำหนดด้วย เพื่อหลีกเลี่ยงการล้อเล่นเช่นนั้นผมไปกับ SYSTEM_VERSION_LESS_THAN (V) แมโครจาก yasirmturk
Cœur

7
ไม่, แต่ Apple จะเพิ่มNSFoundationVersionNumber_iOS_8_0ใน iOS 9 เพียงตรวจสอบ NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1
CarlJ

111

การเริ่มต้น Xcode 9 ในObjective-C :

if (@available(iOS 11, *)) {
    // iOS 11 (or newer) ObjC code
} else {
    // iOS 10 or older code
}

การเริ่ม Xcode 7 ในSwift :

if #available(iOS 11, *) {
    // iOS 11 (or newer) Swift code
} else {
    // iOS 10 or older code
}

สำหรับเวอร์ชันคุณสามารถระบุ MAJOR, MINOR หรือ PATCH (ดูที่http://semver.org/สำหรับคำจำกัดความ) ตัวอย่าง:

  • iOS 11และiOS 11.0เป็นเวอร์ชั่นขั้นต่ำสุดเดียวกัน
  • iOS 10, iOS 10.3, iOS 10.3.1เป็นรุ่นที่แตกต่างกันน้อยที่สุด

คุณสามารถป้อนค่าสำหรับระบบใด ๆ เหล่านี้:

  • iOS, macOS, watchOS,tvOS

ตัวอย่างกรณีจริงนำมาจากหนึ่งในฝักของฉัน :

if #available(iOS 10.0, tvOS 10.0, *) {
    // iOS 10+ and tvOS 10+ Swift code
} else {
    // iOS 9 and tvOS 9 older code
}

เอกสาร


สิ่งนี้สามารถกลับด้านได้ใน Objective-C หรือ Swift
Legoless

@Legolessif (...) {} else { ... }
Cœur

ฉันสามารถใช้guardใน Objective-C แทนที่จะปล่อยให้บล็อกเปิดและเยื้องในelseคำสั่งได้หรือไม่
Legoless

@Legoless ไม่เพียงใช้ที่ว่างเปล่าบล็อกตามif else
Cœur

1
นั่นเป็นคำตอบที่ฉันมีอยู่ในขณะนี้เพียงต้องการหลีกเลี่ยงการเยื้องและifบล็อกว่างเปล่าที่ไม่จำเป็น
Legoless

45

สิ่งนี้ใช้เพื่อตรวจสอบเวอร์ชั่น SDK ที่ใช้งานร่วมกันได้ใน Xcode นี่คือถ้าคุณมีทีมใหญ่ที่มี Xcode รุ่นต่าง ๆ หรือหลายโครงการที่สนับสนุน SDK ที่แตกต่างกันซึ่งใช้รหัสเดียวกัน:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
  //programming in iOS 8+ SDK here
#else
  //programming in lower than iOS 8 here   
#endif

สิ่งที่คุณต้องการคือการตรวจสอบเวอร์ชั่น iOS บนอุปกรณ์ คุณสามารถทำได้ด้วยสิ่งนี้:

if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
  //older than iOS 8 code here
} else {
  //iOS 8 specific code here
}

รุ่น Swift:

if let version = Float(UIDevice.current.systemVersion), version < 9.3 {
    //add lower than 9.3 code here
} else {
    //add 9.3 and above code here
}

Swift เวอร์ชันปัจจุบันควรใช้สิ่งนี้:

if #available(iOS 12, *) {
    //iOS 12 specific code here
} else {
    //older than iOS 12 code here
}

37

ลอง:

NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: @"3.1.3" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending) {
    // OS version >= 3.1.3
} else {
    // OS version < 3.1.3
}

2
ทำไมไม่กลับคำสั่งซื้อที่นี่และบันทึกการเปรียบเทียบเนื่องจากทั้ง @ "3.1.3" และ systemVersion เป็น NSStrings Ie: `if ([@" 3.1.3 "เปรียบเทียบ: [UIDevice currentDevice] .systemVersion ตัวเลือก: NSNumericSearch] == NSOrderedDescending); // เวอร์ชั่น OS> = 3.1.3 อื่น; // รุ่น OS <3.1.3`
Rob

3
การทำเช่นนั้นอาจทำให้ตรรกะชัดเจนน้อยลง อย่างไรก็ตามการปฏิบัติงานควรมีความเท่าเทียมกัน
Jonathan Grynspan

1
การเปรียบเทียบระหว่างจำนวนเต็มสองจำนวนนั้นไม่แพงอย่างแน่นอน
KPM

มันเป็นเรื่องของสไตล์จริงๆ ค่าใช้จ่ายในการกระจายข้อความจะมีมากกว่าการเปรียบเทียบจำนวนเต็มพิเศษอย่างมากมาย
Jonathan Grynspan

35

วิธีการที่ต้องการ

ใน Swift 2.0 Apple เพิ่มการตรวจสอบความพร้อมใช้งานโดยใช้ไวยากรณ์ที่สะดวกกว่า (อ่านเพิ่มเติมที่นี่ ) ตอนนี้คุณสามารถตรวจสอบเวอร์ชั่นของระบบปฏิบัติการด้วยไวยากรณ์ที่สะอาดขึ้น:

if #available(iOS 9, *) {
    // Then we are on iOS 9
} else {
    // iOS 8 or earlier
}

สิ่งนี้เป็นที่ต้องการมากกว่าการตรวจสอบrespondsToSelectorฯลฯ ( มีอะไรใหม่ใน Swift ) ตอนนี้คอมไพเลอร์จะเตือนคุณหากคุณไม่ได้ป้องกันรหัสของคุณอย่างถูกต้อง


Pre Swift 2.0

สิ่งใหม่ใน iOS 8 NSProcessInfoช่วยให้สามารถตรวจสอบเวอร์ชัน semantic ได้ดีขึ้น

การปรับใช้บน iOS 8 และสูงกว่า

สำหรับเป้าหมายการใช้งานขั้นต่ำของiOS 8.0หรือสูงกว่าการใช้งานหรือNSProcessInfo operatingSystemVersionisOperatingSystemAtLeastVersion

สิ่งนี้จะให้ผลดังนี้:

let minimumVersion = NSOperatingSystemVersion(majorVersion: 8, minorVersion: 1, patchVersion: 2)
if NSProcessInfo().isOperatingSystemAtLeastVersion(minimumVersion) {
    //current version is >= (8.1.2)
} else {
    //current version is < (8.1.2)
}

การปรับใช้บน iOS 7

สำหรับเป้าหมายการใช้งานขั้นต่ำของiOS 7.1หรือต่ำกว่าใช้เปรียบเทียบกับ ในNSStringCompareOptions.NumericSearchUIDevice systemVersion

สิ่งนี้จะทำให้:

let minimumVersionString = "3.1.3"
let versionComparison = UIDevice.currentDevice().systemVersion.compare(minimumVersionString, options: .NumericSearch)
switch versionComparison {
    case .OrderedSame, .OrderedDescending:
        //current version is >= (3.1.3)
        break
    case .OrderedAscending:
        //current version is < (3.1.3)
        fallthrough
    default:
        break;
}

อ่านเพิ่มเติมได้ที่NSHipster


9

ฉันจะเก็บไว้ในไฟล์ Constants.h ของฉัน:

#define IS_IPHONE5 (([[UIScreen mainScreen] bounds].size.height-568)?NO:YES) 
#define IS_OS_5_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0)
#define IS_OS_6_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)
#define IS_OS_7_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
#define IS_OS_8_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

ยิ่งใหญ่ ดีกว่าที่จะวางสิ่งนี้ไว้ใน.pchไฟล์โครงการ XCode ของคุณ
Vaibhav Jhaveri

1
ฉันวางค่าคงที่ทั้งหมดไว้ในConstants.hไฟล์ที่นำเข้ามาในpchไฟล์ของฉัน
Segev

6
+(BOOL)doesSystemVersionMeetRequirement:(NSString *)minRequirement{

// eg  NSString *reqSysVer = @"4.0";


  NSString *currSysVer = [[UIDevice currentDevice] systemVersion];

  if ([currSysVer compare:minRequirement options:NSNumericSearch] != NSOrderedAscending)
  {
    return YES;
  }else{
    return NO;
  }


}

@Jef Periods ไม่ใช่จุดทศนิยมในการกำหนดเวอร์ชันและมีความเกี่ยวข้อง คำตอบของคุณจะไม่เพิกเฉยต่อช่วงเวลามันจะล้มเหลวถ้าเป็นเช่นนั้น ในการกำหนดเวอร์ชันองค์ประกอบที่แยกแต่ละงวดจะเป็นจำนวนเต็ม ตัวอย่าง: '1.23.45' มากกว่า '1.2.345' เนื่องจากองค์ประกอบที่สอง '23' มากกว่า '2' ถ้าคุณจะกำจัดจุดมันจะเป็นจำนวนเดียวกัน
Andres Canella

6

ด้วยคลาสVersionที่อยู่ในโปรเจ็กต์nv-ios (Apache License, เวอร์ชั่น 2.0) ทำให้ง่ายต่อการรับและเปรียบเทียบเวอร์ชั่น iOS ตัวอย่างโค้ดด้านล่างจะทิ้งเวอร์ชัน iOS และตรวจสอบว่าเวอร์ชันนั้นมากกว่าหรือเท่ากับ 6.0

// Get the system version of iOS at runtime.
NSString *versionString = [[UIDevice currentDevice] systemVersion];

// Convert the version string to a Version instance.
Version *version = [Version versionWithString:versionString];

// Dump the major, minor and micro version numbers.
NSLog(@"version = [%d, %d, %d]",
    version.major, version.minor, version.micro);

// Check whether the version is greater than or equal to 6.0.
if ([version isGreaterThanOrEqualToMajor:6 minor:0])
{
    // The iOS version is greater than or equal to 6.0.
}

// Another way to check whether iOS version is
// greater than or equal to 6.0.
if (6 <= version.major)
{
    // The iOS version is greater than or equal to 6.0.
}

โครงการหน้า: NV-iOS รุ่น
TakahikoKawasaki / NV-iOS รุ่น

บล็อก: รับและเปรียบเทียบเวอร์ชัน iOS ที่รันไทม์พร้อมคลาสเวอร์ชันรับ
และเปรียบเทียบเวอร์ชัน iOS ที่รันไทม์กับคลาสเวอร์ชัน


5

วิธีใหม่ในการตรวจสอบเวอร์ชั่นของระบบโดยใช้ swift Forget [[UIDevice currentDevice] systemVersion] และ NSFoundationVersionNumber หมายเลข

เราสามารถใช้ NSProcessInfo -isOperatingSystemAtLeastVersion

     import Foundation

     let yosemite = NSOperatingSystemVersion(majorVersion: 10, minorVersion: 10, patchVersion: 0)
     NSProcessInfo().isOperatingSystemAtLeastVersion(yosemite) // false

5

UIDevice + IOSVersion.h

@interface UIDevice (IOSVersion)

+ (BOOL)isCurrentIOSVersionEqualToVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionGreaterThanVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionGreaterThanOrEqualToVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionLessThanVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionLessThanOrEqualToVersion:(NSString *)iOSVersion

@end

UIDevice + IOSVersion.m

#import "UIDevice+IOSVersion.h"

@implementation UIDevice (IOSVersion)

+ (BOOL)isCurrentIOSVersionEqualToVersion:(NSString *)iOSVersion
{
    return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] == NSOrderedSame;
}

+ (BOOL)isCurrentIOSVersionGreaterThanVersion:(NSString *)iOSVersion
{
    return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] == NSOrderedDescending;
}

+ (BOOL)isCurrentIOSVersionGreaterThanOrEqualToVersion:(NSString *)iOSVersion
{
    return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] != NSOrderedAscending;
}

+ (BOOL)isCurrentIOSVersionLessThanVersion:(NSString *)iOSVersion
{
    return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] == NSOrderedAscending;
}

+ (BOOL)isCurrentIOSVersionLessThanOrEqualToVersion:(NSString *)iOSVersion
{
    return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] != NSOrderedDescending;
}

@end

4

โดยทั่วไปจะเป็นการดีกว่าถ้าถามว่าวัตถุสามารถเลือกตัวเลือกได้หรือไม่แทนที่จะตรวจสอบหมายเลขเวอร์ชันเพื่อตัดสินใจว่าจะต้องมีวัตถุอยู่หรือไม่

เมื่อนี่ไม่ใช่ตัวเลือกคุณจะต้องระมัดระวังที่นี่เพราะ[@"5.0" compare:@"5" options:NSNumericSearch]ผลตอบแทนNSOrderedDescendingที่อาจไม่ได้มีความตั้งใจ ฉันคาดหวังNSOrderedSameที่นี่ อย่างน้อยนี่เป็นข้อกังวลทางทฤษฎีอย่างหนึ่งที่คุ้มค่าที่จะป้องกันในความคิดของฉัน

สิ่งที่ควรพิจารณาอีกอย่างคือความเป็นไปได้ของการป้อนข้อมูลเวอร์ชันที่ไม่ดีซึ่งไม่สามารถเปรียบเทียบได้อย่างสมเหตุสมผล แอปเปิ้ลซัพพลายสามค่าคงที่ที่กำหนดไว้ล่วงหน้าNSOrderedAscending, NSOrderedSameและNSOrderedDescendingแต่ผมอาจจะคิดว่าการใช้งานสำหรับบางสิ่งบางอย่างที่เรียกว่าNSOrderedUnorderedในกรณีที่ผมไม่สามารถเปรียบเทียบสองสิ่งและฉันต้องการที่จะกลับมาเป็นค่าบ่งชี้นี้

ยิ่งไปกว่านั้นมันเป็นไปไม่ได้ที่ Apple จะขยายค่าคงที่ที่กำหนดไว้ล่วงหน้าสามวันเพื่อให้ค่าตอบแทนต่าง ๆ ทำให้การเปรียบเทียบ!= NSOrderedAscendingไม่ฉลาด

ด้วยวิธีนี้กล่าวว่าพิจารณารหัสต่อไปนี้

typedef enum {kSKOrderedNotOrdered = -2, kSKOrderedAscending = -1, kSKOrderedSame = 0, kSKOrderedDescending = 1} SKComparisonResult;

@interface SKComparator : NSObject
+ (SKComparisonResult)comparePointSeparatedVersionNumber:(NSString *)vOne withPointSeparatedVersionNumber:(NSString *)vTwo;
@end

@implementation SKComparator
+ (SKComparisonResult)comparePointSeparatedVersionNumber:(NSString *)vOne withPointSeparatedVersionNumber:(NSString *)vTwo {
  if (!vOne || !vTwo || [vOne length] < 1 || [vTwo length] < 1 || [vOne rangeOfString:@".."].location != NSNotFound ||
    [vTwo rangeOfString:@".."].location != NSNotFound) {
    return SKOrderedNotOrdered;
  }
  NSCharacterSet *numericalCharSet = [NSCharacterSet characterSetWithCharactersInString:@".0123456789"];
  NSString *vOneTrimmed = [vOne stringByTrimmingCharactersInSet:numericalCharSet];
  NSString *vTwoTrimmed = [vTwo stringByTrimmingCharactersInSet:numericalCharSet];
  if ([vOneTrimmed length] > 0 || [vTwoTrimmed length] > 0) {
    return SKOrderedNotOrdered;
  }
  NSArray *vOneArray = [vOne componentsSeparatedByString:@"."];
  NSArray *vTwoArray = [vTwo componentsSeparatedByString:@"."];
  for (NSUInteger i = 0; i < MIN([vOneArray count], [vTwoArray count]); i++) {
    NSInteger vOneInt = [[vOneArray objectAtIndex:i] intValue];
    NSInteger vTwoInt = [[vTwoArray objectAtIndex:i] intValue];
    if (vOneInt > vTwoInt) {
      return kSKOrderedDescending;
    } else if (vOneInt < vTwoInt) {
      return kSKOrderedAscending;
    }
  }
  if ([vOneArray count] > [vTwoArray count]) {
    for (NSUInteger i = [vTwoArray count]; i < [vOneArray count]; i++) {
      if ([[vOneArray objectAtIndex:i] intValue] > 0) {
        return kSKOrderedDescending;
      }
    }
  } else if ([vOneArray count] < [vTwoArray count]) {
    for (NSUInteger i = [vOneArray count]; i < [vTwoArray count]; i++) {
      if ([[vTwoArray objectAtIndex:i] intValue] > 0) {
        return kSKOrderedAscending;
      }
    }
  }
  return kSKOrderedSame;
}
@end

4
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
        // Your code here
}

แน่นอนNSFoundationVersionNumber_iOS_6_1ต้องเปลี่ยนเป็นใช้กับเวอร์ชัน iOS ที่คุณต้องการตรวจสอบ สิ่งที่ฉันได้เขียนไว้ตอนนี้อาจจะมีการใช้งานจำนวนมากเมื่อทำการทดสอบว่าอุปกรณ์กำลังใช้ iOS7 หรือรุ่นก่อนหน้า


4

สายไปงานเลี้ยงเล็กน้อย แต่ด้วย iOS 8.0 ออกมาตรงนี้อาจเกี่ยวข้องกัน

หากคุณสามารถหลีกเลี่ยงการใช้

[[UIDevice currentDevice] systemVersion]

แทนที่จะตรวจสอบว่ามีเมธอด / คลาส / อะไรก็ตาม

if ([self.yourClassInstance respondsToSelector:@selector(<yourMethod>)]) 
{ 
    //do stuff 
}

ฉันพบว่ามันจะมีประโยชน์สำหรับผู้จัดการสถานที่ที่ฉันต้องโทรร้องขอเมื่อInInseAuthorizationสำหรับ iOS 8.0 แต่วิธีนี้ใช้ไม่ได้กับ iOS <8



3

ฉันรู้ว่านี้เป็นคำถามที่เก่า Availability.hแต่คนที่ควรจะได้กล่าวถึงแมโครรวบรวมเวลาใน วิธีอื่นทั้งหมดที่นี่เป็นโซลูชั่นรันไทม์และจะไม่ทำงานในไฟล์ส่วนหัวหมวดหมู่คลาสหรือคำจำกัดความของ ivar

สำหรับสถานการณ์เหล่านี้ให้ใช้

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

h / t คำตอบนี้


3
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

จากนั้นเพิ่มเงื่อนไข if ดังนี้: -

if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
   //Your code
}       

2

มีรุ่นเช่น 7.0 หรือ 6.0.3 ดังนั้นเราสามารถแปลงเวอร์ชันเป็นตัวเลขเพื่อเปรียบเทียบ หากเวอร์ชันเป็น 7.0 ให้เพิ่ม ".0" ต่อท้ายจากนั้นนำค่าตัวเลข

 int version;
 NSString* iosVersion=[[UIDevice currentDevice] systemVersion];
 NSArray* components=[iosVersion componentsSeparatedByString:@"."];
 if ([components count]==2) {
    iosVersion=[NSString stringWithFormat:@"%@.0",iosVersion];

 }
 iosVersion=[iosVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
 version=[iosVersion integerValue];

สำหรับ 6.0.0

  if (version==600) {
    // Do something
  }

สำหรับ 7.0

 if (version==700) {
   // Do something
 }

เพียงแค่ลบจุดทศนิยมเป็นวิธีที่ผิด พิจารณาองค์ประกอบที่เป็นมากกว่า 1 6.1.10ตัวอักษรยาวเช่น ดังนั้นอัลกอริทึมนี้จะให้ผล6110 > 700ซึ่งไม่ถูกต้อง
เริ่ม

ฉันเข้าใจว่าแอปเปิ้ลไม่ดีในการเปิดตัวเวอร์ชั่นใหม่ แต่ในจำนวนที่สองของเวลาส่วนใหญ่ไม่เคยเกิน 5 ดังนั้น 10 จึงหมดคำถาม นี่เป็นแนวทางแบบ adhoc ดังนั้นถ้ามันจัดการกับ case สำหรับ 2 คอมโพเนนต์คุณสามารถแก้ไขมันเพื่อจัดการสี่ case aswel หากคุณต้องการทำด้วยตนเอง อย่างไรก็ตามวิธีการนี้ได้รับการแสดงความคิดเห็นในเวลาที่ iOS6 หรือ 7 iOS 9 และ 10 มีวิธีที่ดีกว่ามากในการตรวจสอบเช่น #available
NaXir



1

ในฐานะที่เป็นรูปแบบของโซลูชัน 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

ใช้วิธีการแนะนำที่อ้างถึง ... หากไม่มีคำจำกัดความในไฟล์ส่วนหัวคุณสามารถรับรุ่นที่พิมพ์บนคอนโซลด้วยอุปกรณ์ของ 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

โซลูชันสำหรับการตรวจสอบเวอร์ชั่น 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 คุณจะสังเกตเห็นว่าคุณจะไม่ผ่านส่วนอื่น ๆ ของรหัส


ทำไมต้องลงคะแนน โซลูชันนี้ทำงานได้อย่างสมบูรณ์แบบโดยใช้ Swift และ iOS ทุกรุ่น โดยเฉพาะอย่างยิ่งการตรวจสอบการดำรงอยู่ของชั้นเรียนนั้นสมบูรณ์แบบ
King-Wizard


0

รุ่นทั่วไปมากขึ้นใน Obj-C ++ 11 (คุณอาจแทนที่บางสิ่งด้วยฟังก์ชัน NSString / C แต่นี่เป็น verbose น้อยกว่าซึ่งจะให้กลไกสองอย่างคุณ 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
float deviceOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
float versionToBeCompared = 3.1.3; //(For Example in your case)

if(deviceOSVersion < versionToBeCompared)
   //Do whatever you need to do. Device version is lesser than 3.1.3(in your case)
else 
   //Device version should be either equal to the version you specified or above

float versionToBeCompared = 3.1.3;ไม่สามารถคอมไพล์ได้
ปาง

0

ตัวอย่างรวดเร็วที่ใช้งานได้จริง:

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

อย่าใช้ NSProcessInfo เพราะมันใช้ไม่ได้กับ 8.0 ดังนั้นมันจึงไร้ประโยชน์มากจนถึงปี 2559


0

นี่คือเวอร์ชั่นที่รวดเร็ว:

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
}

ฉันคิดว่าเวอร์ชั่นควรเป็น iOSVersion ในบรรทัดที่ 3-6 เช่นกัน struct iOSVersion { static let SYS_VERSION_FLOAT = (UIDevice.currentDevice().systemVersion as NSString).floatValue static let iOS7 = (iOSVersion.SYS_VERSION_FLOAT < 8.0 && iOSVersion.SYS_VERSION_FLOAT >= 7.0) static let iOS8 = (iOSVersion.SYS_VERSION_FLOAT >= 8.0 && iOSVersion.SYS_VERSION_FLOAT < 9.0) static let iOS9 = (iOSVersion.SYS_VERSION_FLOAT >= 9.0 && iOSVersion.SYS_VERSION_FLOAT < 10.0) }
Kastor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.