Saya menulis aplikasi yang menerima data dengan item dan nomor versi. Angka-angka tersebut memiliki format seperti "1.0.1" atau "1.2.5". Bagaimana cara membandingkan nomor versi ini? Saya pikir mereka harus diformat sebagai string terlebih dahulu, bukan? Opsi apa yang saya miliki untuk menentukan bahwa "1.2.5" muncul setelah "1.0.1"?
objective-c
comparison
mlecho
sumber
sumber
Jawaban:
Ini adalah cara termudah untuk membandingkan versi, dengan mengingat bahwa "1" <"1.0" <"1.0.0":
NSString* requiredVersion = @"1.2.0"; NSString* actualVersion = @"1.1.5"; if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) { // actualVersion is lower than the requiredVersion }
sumber
componentsSeparatedByString
pendekatan). Anda dapat menguji ini sendiri dengan@"1.8"
vs@"1.7.2.3.55"
dan melihat bahwa 1,8 keluar lebih dulu.Saya akan menambahkan metode saya, yang membandingkan secara ketat versi numerik (no a, b, RC dll.) Dengan sejumlah komponen.
+ (NSComparisonResult)compareVersion:(NSString*)versionOne toVersion:(NSString*)versionTwo { NSArray* versionOneComp = [versionOne componentsSeparatedByString:@"."]; NSArray* versionTwoComp = [versionTwo componentsSeparatedByString:@"."]; NSInteger pos = 0; while ([versionOneComp count] > pos || [versionTwoComp count] > pos) { NSInteger v1 = [versionOneComp count] > pos ? [[versionOneComp objectAtIndex:pos] integerValue] : 0; NSInteger v2 = [versionTwoComp count] > pos ? [[versionTwoComp objectAtIndex:pos] integerValue] : 0; if (v1 < v2) { return NSOrderedAscending; } else if (v1 > v2) { return NSOrderedDescending; } pos++; } return NSOrderedSame; }
sumber
Ini adalah perluasan jawaban Nathan de Vries untuk mengatasi masalah 1 <1.0 <1.0.0 dll.
Pertama kita bisa mengatasi masalah ekstra ".0" pada string versi kita dengan
NSString
kategori:@implementation NSString (VersionNumbers) - (NSString *)shortenedVersionNumberString { static NSString *const unnecessaryVersionSuffix = @".0"; NSString *shortenedVersionNumber = self; while ([shortenedVersionNumber hasSuffix:unnecessaryVersionSuffix]) { shortenedVersionNumber = [shortenedVersionNumber substringToIndex:shortenedVersionNumber.length - unnecessaryVersionSuffix.length]; } return shortenedVersionNumber; } @end
Dengan
NSString
kategori di atas kita dapat mempersingkat nomor versi kita untuk menghilangkan .0 yang tidak perluNSString* requiredVersion = @"1.2.0"; NSString* actualVersion = @"1.1.5"; requiredVersion = [requiredVersion shortenedVersionNumberString]; // now 1.2 actualVersion = [actualVersion shortenedVersionNumberString]; // still 1.1.5
Sekarang kita masih dapat menggunakan pendekatan sederhana yang indah yang diusulkan oleh Nathan de Vries:
if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) { // actualVersion is lower than the requiredVersion }
sumber
Saya membuatnya sendiri, menggunakan Kategori ..
Sumber..
@implementation NSString (VersionComparison) - (NSComparisonResult)compareVersion:(NSString *)version{ NSArray *version1 = [self componentsSeparatedByString:@"."]; NSArray *version2 = [version componentsSeparatedByString:@"."]; for(int i = 0 ; i < version1.count || i < version2.count; i++){ NSInteger value1 = 0; NSInteger value2 = 0; if(i < version1.count){ value1 = [version1[i] integerValue]; } if(i < version2.count){ value2 = [version2[i] integerValue]; } if(value1 == value2){ continue; }else{ if(value1 > value2){ return NSOrderedDescending; }else{ return NSOrderedAscending; } } } return NSOrderedSame; }
Uji..
NSString *version1 = @"3.3.1"; NSString *version2 = @"3.12.1"; NSComparisonResult result = [version1 compareVersion:version2]; switch (result) { case NSOrderedAscending: case NSOrderedDescending: case NSOrderedSame: break; }
sumber
Sparkle (kerangka pembaruan perangkat lunak paling populer untuk MacOS) memiliki kelas SUStandardVersionComparator yang melakukan ini, dan juga memperhitungkan nomor build dan penanda beta. Yaitu dengan benar membandingkan
1.0.5 > 1.0.5b7
atau2.0 (2345) > 2.0 (2100)
. Kode hanya menggunakan Foundation, jadi harus berfungsi dengan baik di iOS juga.sumber
Lihat kategori NSString saya yang menerapkan pemeriksaan versi mudah di github; https://github.com/stijnster/NSString-compareToVersion
[@"1.2.2.4" compareToVersion:@"1.2.2.5"];
Ini akan mengembalikan NSComparisonResult yang lebih akurat daripada menggunakan;
[@"1.2.2" compare:@"1.2.2.5" options:NSNumericSearch]
Pembantu juga ditambahkan;
[@"1.2.2.4" isOlderThanVersion:@"1.2.2.5"]; [@"1.2.2.4" isNewerThanVersion:@"1.2.2.5"]; [@"1.2.2.4" isEqualToVersion:@"1.2.2.5"]; [@"1.2.2.4" isEqualOrOlderThanVersion:@"1.2.2.5"]; [@"1.2.2.4" isEqualOrNewerThanVersion:@"1.2.2.5"];
sumber
Versi Swift 2.2:
let currentStoreAppVersion = "1.10.2" let minimumAppVersionRequired = "1.2.2" if currentStoreAppVersion.compare(minimumAppVersionRequired, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending { print("Current Store version is higher") } else { print("Latest New version is higher") }
Versi Swift 3:
let currentStoreVersion = "1.1.0.2" let latestMinimumAppVersionRequired = "1.1.1" if currentStoreVersion.compare(latestMinimumAppVersionRequired, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending { print("Current version is higher") } else { print("Latest version is higher") }
sumber
let currentVersion = "1.2.0" let oldVersion = "1.1.1" if currentVersion.compare(oldVersion, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending { print("Higher") } else { print("Lower") }
sumber
Saya pikir saya hanya akan berbagi fungsi yang saya kumpulkan untuk ini. Itu sama sekali tidak sempurna. Silakan lihat contoh dan hasilnya. Tetapi jika Anda memeriksa nomor versi Anda sendiri (yang harus saya lakukan untuk mengelola hal-hal seperti migrasi database) maka ini mungkin sedikit membantu.
(juga, hapus pernyataan log dalam metode, tentu saja. itu ada untuk membantu Anda melihat apa yang dilakukannya itu semua)
Tes:
[self isVersion:@"1.0" higherThan:@"0.1"]; [self isVersion:@"1.0" higherThan:@"0.9.5"]; [self isVersion:@"1.0" higherThan:@"0.9.5.1"]; [self isVersion:@"1.0.1" higherThan:@"1.0"]; [self isVersion:@"1.0.0" higherThan:@"1.0.1"]; [self isVersion:@"1.0.0" higherThan:@"1.0.0"]; // alpha tests [self isVersion:@"1.0b" higherThan:@"1.0a"]; [self isVersion:@"1.0a" higherThan:@"1.0b"]; [self isVersion:@"1.0a" higherThan:@"1.0a"]; [self isVersion:@"1.0" higherThan:@"1.0RC1"]; [self isVersion:@"1.0.1" higherThan:@"1.0RC1"];
Hasil:
1.0 > 0.1 1.0 > 0.9.5 1.0 > 0.9.5.1 1.0.1 > 1.0 1.0.0 < 1.0.1 1.0.0 == 1.0.0 1.0b > 1.0a 1.0a < 1.0b 1.0a == 1.0a 1.0 < 1.0RC1 <-- FAILURE 1.0.1 < 1.0RC1 <-- FAILURE
perhatikan bahwa alfa berfungsi tetapi Anda harus sangat berhati-hati dengannya. sekali Anda menjadi alfa di beberapa titik, Anda tidak dapat memperpanjangnya dengan mengubah nomor kecil lainnya di belakangnya.
Kode:
- (BOOL) isVersion:(NSString *)thisVersionString higherThan:(NSString *)thatVersionString { // LOWER if ([thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedAscending) { NSLog(@"%@ < %@", thisVersionString, thatVersionString); return NO; } // EQUAL if ([thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedSame) { NSLog(@"%@ == %@", thisVersionString, thatVersionString); return NO; } NSLog(@"%@ > %@", thisVersionString, thatVersionString); // HIGHER return YES; }
sumber
Perpustakaan iOS saya AppUpdateTracker berisi kategori NSString untuk melakukan perbandingan semacam ini. (Implementasi didasarkan pada jawaban DonnaLea .)
Penggunaannya adalah sebagai berikut:
[@"1.4" isGreaterThanVersionString:@"1.3"]; // YES [@"1.4" isLessThanOrEqualToVersionString:@"1.3"]; // NO
Selain itu, Anda dapat menggunakannya untuk melacak status penginstalan / pembaruan aplikasi Anda:
[AppUpdateTracker registerForAppUpdatesWithBlock:^(NSString *previousVersion, NSString *currentVersion) { NSLog(@"app updated from: %@ to: %@", previousVersion, currentVersion); }]; [AppUpdateTracker registerForFirstInstallWithBlock:^(NSTimeInterval installTimeSinceEpoch, NSUInteger installCount) { NSLog(@"first install detected at: %f amount of times app was (re)installed: %lu", installTimeSinceEpoch, (unsigned long)installCount); }]; [AppUpdateTracker registerForIncrementedUseCountWithBlock:^(NSUInteger useCount) { NSLog(@"incremented use count to: %lu", (unsigned long)useCount); }];
sumber
Glibc memiliki fungsi
strverscmp
danversionsort
… sayangnya, tidak portabel untuk iPhone, tetapi Anda dapat menulis sendiri dengan cukup mudah. Implementasi ulang (belum teruji) ini berasal dari hanya membaca perilaku yang didokumentasikan, dan bukan dari membaca kode sumber Glibc.int strverscmp(const char *s1, const char *s2) { const char *b1 = s1, *b2 = s2, *e1, *e2; long n1, n2; size_t z1, z2; while (*b1 && *b1 == *b2) b1++, b2++; if (!*b1 && !*b2) return 0; e1 = b1, e2 = b2; while (b1 > s1 && isdigit(b1[-1])) b1--; while (b2 > s2 && isdigit(b2[-1])) b2--; n1 = strtol(b1, &e1, 10); n2 = strtol(b2, &e2, 10); if (b1 == e1 || b2 == e2) return strcmp(s1, s2); if (n1 < n2) return -1; if (n1 > n2) return 1; z1 = strspn(b1, "0"), z2 = strspn(b2, "0"); if (z1 > z2) return -1; if (z1 < z2) return 1; return 0; }
sumber
Jika Anda tahu bahwa setiap nomor versi akan memiliki tepat 3 bilangan bulat yang dipisahkan oleh titik, Anda dapat menguraikannya (misalnya menggunakan
sscanf(3)
) dan membandingkannya:const char *version1str = "1.0.1"; const char *version2str = "1.2.5"; int major1, minor1, patch1; int major2, minor2, patch2; if(sscanf(version1str, "%d.%d.%d", &major1, &minor1, &patch1) == 3 && sscanf(version2str, "%d.%d.%d", &major2, &minor2, &patch2) == 3) { // Parsing succeeded, now compare the integers if(major1 > major2 || (major1 == major2 && (minor1 > minor2 || (minor1 == minor2 && patch1 > patch2)))) { // version1 > version2 } else if(major1 == major2 && minor1 == minor2 && patch1 == patch2) { // version1 == version2 } else { // version1 < version2 } } else { // Handle error, parsing failed }
sumber
Untuk memeriksa versi dengan cepat Anda dapat menggunakan berikut ini
switch newVersion.compare(currentversion, options: NSStringCompareOptions.NumericSearch) { case .OrderedDescending: println("NewVersion available ") // Show Alert Here case .OrderedAscending: println("NewVersion Not available ") default: println("default") }
Semoga bermanfaat.
sumber
Berikut adalah fungsi rekursif yang bekerja dengan beberapa versi format dengan panjang berapa pun. Ini juga berfungsi untuk @ "1.0" dan @ "1.0.0"
static inline NSComparisonResult versioncmp(const NSString * a, const NSString * b) { if ([a isEqualToString:@""] && [b isEqualToString:@""]) { return NSOrderedSame; } if ([a isEqualToString:@""]) { a = @"0"; } if ([b isEqualToString:@""]) { b = @"0"; } NSArray<NSString*> * aComponents = [a componentsSeparatedByString:@"."]; NSArray<NSString*> * bComponents = [b componentsSeparatedByString:@"."]; NSComparisonResult r = [aComponents[0] compare:bComponents[0] options:NSNumericSearch]; if(r != NSOrderedSame) { return r; } else { NSString* newA = (a.length == aComponents[0].length) ? @"" : [a substringFromIndex:aComponents[0].length+1]; NSString* newB = (b.length == bComponents[0].length) ? @"" : [b substringFromIndex:bComponents[0].length+1]; return versioncmp(newA, newB); } }
Sampel uji:
versioncmp(@"11.5", @"8.2.3"); versioncmp(@"1.5", @"8.2.3"); versioncmp(@"1.0", @"1.0.0"); versioncmp(@"11.5.3.4.1.2", @"11.5.3.4.1.2");
sumber