比较Objective-C中的版本号

我正在写一个应用程序接收数据的项目和版本号。 数字格式化为“1.0.1”或“1.2.5”。 我怎样才能比较这些版本号? 我认为他们必须首先格式化为string,不是吗? 我有什么select来确定“1.2.5”在“1.0.1”之后?

这是比较版本的最简单的方法,牢记“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 } 

我将添加我的方法,它比较严格的数字版本(没有a,b,RC等)与任何数量的组件。

 + (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; } 

这是Nathan de Vries的一个扩展,以解决1 <1.0 <1.0.0等问题。

首先,我们可以在我们的版本string上用一个NSString类来解决额外的“.0”的问题:

 @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 

有了上面的NSString类别,我们可以缩短我们的版本号来删除不必要的.0

 NSString* requiredVersion = @"1.2.0"; NSString* actualVersion = @"1.1.5"; requiredVersion = [requiredVersion shortenedVersionNumberString]; // now 1.2 actualVersion = [actualVersion shortenedVersionNumberString]; // still 1.1.5 

现在我们仍然可以使用Nathan de Vries提出的简单方法:

 if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) { // actualVersion is lower than the requiredVersion } 

Sparkle (MacOS最stream行的软件更新框架)有一个SUStandardVersionComparator类来完成这个工作,同时也考虑了内部版本号和beta标记。 即它正确地比较1.0.5 > 1.0.5b72.0 (2345) > 2.0 (2100) 。 代码只使用基础,所以应该在iOS上也能正常工作。

我自己做的,使用类别..

资源..

 @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; } 

testing..

 NSString *version1 = @"3.3.1"; NSString *version2 = @"3.12.1"; NSComparisonResult result = [version1 compareVersion:version2]; switch (result) { case NSOrderedAscending: case NSOrderedDescending: case NSOrderedSame: break; } 

我以为我会分享一个我为此一起工作的function。 这并不完美。 请看看例子和结果。 但是,如果你正在检查你自己的版本号(我必须做的事情,如数据库迁移pipe理),那么这可能会有所帮助。

(当然,也可以删除方法中的日志语句,这些语句可以帮助您查看所做的事情)

testing:

 [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"]; 

结果:

 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 

注意alpha的作品,但是你必须非常小心。 一旦你在某个时候去了阿尔法,你不能通过改变它后面的任何其他次要数字来延长这一点。

码:

 - (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; } 

我的iOS库AppUpdateTracker包含一个NSString类来执行这种比较。 (执行是基于DonnaLea的回答 。)

看看我的NSString类别,实现简单的版本检查github; https://github.com/stijnster/NSString-compareToVersion

 [@"1.2.2.4" compareToVersion:@"1.2.2.5"]; 

这将返回一个更精确的NSComparisonResult然后使用;

 [@"1.2.2" compare:@"1.2.2.5" options:NSNumericSearch] 

助手也被添加;

 [@"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"]; 

要在swift中检查版本,可以使用以下命令

 switch newVersion.compare(currentversion, options: NSStringCompareOptions.NumericSearch) { case .OrderedDescending: println("NewVersion available ") // Show Alert Here case .OrderedAscending: println("NewVersion Not available ") default: println("default") } 

希望这可能有帮助。

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") } 

Swift 3版本:

 let currentStoreVersion = "1.1.0.2" let latestMinimumAppVersionRequired = "1.1.1" if currentStoreVersion.compare(laetstMinimumAppVersionRequired, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending { print("Current version is higher") } else { print("Latest version is higher") } 

这个问题与您的问题不尽相同,它提供了有关如何完成问题的见解。

Glibc有一个函数strverscmpversionsort …不幸的是,不能移植到iPhone,但你可以很容易地写你自己的。 这个(未经testing的)重新实现来自于阅读logging的行为,而不是阅读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; } 

我写了这个小型库,可以方便地比较Obj-C中的两个版本的string。 通常在iOS中。

在GitHub页面上有示例和代码

如果你知道每个版本号只有3个由点分隔的整数,你可以parsing它们(例如使用sscanf(3) )并比较它们:

 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 } 

这个问题很老,但仍然相关。 我找不到符合我需求的比较器,所以我创build了自己的。 我在这里分享它的源代码