前段时间,我读到可以使用以下代码片段来比较版本号:
NSString *vesrion_1 = @"1.2.1";
NSString *version_2 = @"1.2.0";
if ([version_1 compare:version_2 options:NSNumericSearch] == NSOrderedAscending) {
...
}
这似乎工作正常,但是一个用户遇到问题,这是由于看似不正确的版本号比较。
我的问题是,在所有情况下使用此技术比较版本号是否安全?上述比较是否有可能在不同的机器上产生不同的结果?
答案 0 :(得分:4)
我在GitHub上开发了一个非常轻巧且易于使用的VersionComparator - 不像其他一些解决方案那样功能丰富,但很容易上手和使用。
BOOL greater = [VersionComparator isVersion:@"2.0.0" greaterThanVersion:@"1.1.0"];
它简单地比较了从主要到构建的数字 - 如果2大于1那么就没有必要进一步比较。
它的目标是尽可能简单地提供前端代码(如上例所示),也不提供具有大量支持代码的类。通常情况下,这就是所需要的。
答案 1 :(得分:3)
我不知道内置会做什么,但我听说Sparkle framework有一个版本比较器。
快速浏览源代码显示SUStandardVersionComparator对象似乎负责它。它符合<SUVersionComparison>
protocol,这意味着您可以像这样使用它:
NSString *versionA = @"1.2.1";
NSString *versionB = @"1.2.0";
id <SUVersionComparison> comparator = [SUStandardVersionComparator defaultComparator];
NSInteger result = [comparator compareVersion:versionA toVersion:versionB];
if (result == NSOrderedSame) {
//versionA == versionB
} else if (result == NSOrderedAscending) {
//versionA < versionB
} else {
//versionA > versionB
}
(注意:代码未经测试并在浏览器中输入。警告执行者)
答案 2 :(得分:3)
NSNumericSearch
应该完全按照您的意愿行事。它处理您期望从版本号中获得的所有情况。对于之前的项目,我为此写了一堆测试用例:
+ (NSComparisonResult)compareBundleVersion:(NSString *)a withBundleVersion:(NSString *)b
{
return [a compare:b options:NSNumericSearch];
}
STAssertEquals(NSOrderedSame, [self compareBundleVersion:@"1" withBundleVersion:@"1"], nil);
STAssertEquals(NSOrderedSame, [self compareBundleVersion:@"1.0" withBundleVersion:@"1.0"], nil);
STAssertEquals(NSOrderedSame, [self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.1.12"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1" withBundleVersion:@"2"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1" withBundleVersion:@"1.1"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1.0" withBundleVersion:@"1.1"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.1.13"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.2.1"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.1" withBundleVersion:@"1"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.1" withBundleVersion:@"1.0"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.1.13" withBundleVersion:@"1.1.12"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.2.1" withBundleVersion:@"1.1.12"], nil);
我还用另一张海报提到的先前案例对此进行了测试:
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.30" withBundleVersion:@"1.3"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.19" withBundleVersion:@"1.3"], nil);
一切都如你期望的那样过去。
答案 3 :(得分:2)
我会说不,这不安全。版本号不是真正的数字,而是数字的层次结构。例如考虑三个版本号:
1.19
1.3
1.30
数字比较会使1.19小于1.3和1.30。它也会说1.3和1.30相等。如果上面是版本号,那几乎肯定不是你想要的。
还存在本地化 * 的问题。在法语中,上面甚至不会解析为数字。
将版本号视为它们是一个独立整数的层次结构,这样做要好得多。您可以使用-componentsSeparatedByString:
* 有点讽刺的是,我的浏览器将本地化的英国英语拼写标记为不正确。
答案 4 :(得分:1)
我喜欢迈克(代码较少)的答案,但即使有关于NSNumericSearch的比较选项的问题,这也应该有效。
- (NSComparisonResult)compareVersion:(NSString *)versionA to:(NSString *)versionB
{
NSArray *versionAComp = [versionA componentsSeparatedByString:@"."];
NSArray *versionBComp = [versionB componentsSeparatedByString:@"."];
__block NSComparisonResult result = NSOrderedSame;
[versionAComp enumerateObjectsUsingBlock:
^(NSString *obj, NSUInteger idx, BOOL *stop)
{
// handle abbreviated versions.
if (idx > versionBComp.count -1)
{
*stop = YES;
return;
}
NSInteger verAInt = [versionAComp[idx] integerValue];
NSInteger verBInt = [versionBComp[idx] integerValue];
if (verAInt != verBInt)
{
if (verAInt < verBInt)
result = NSOrderedAscending;
else
result = NSOrderedDescending;
*stop = YES;
return;
}
}];
return result;
}
答案 5 :(得分:0)
在Java中,您可以使用以下代码段来比较版本。如果一个版本号比另一个版本号短,我们用零标准化它。
import java.util.Arrays;
import java.util.Comparator;
public class FreePlay {
static String[] versions = {"1.5.3.2", "2.3.4", "1.0.3.4", "10.10.1.1", "1.0.2.5", "2.3.4"};
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("Unsorted versions");
for (String s: versions) {
System.out.print("'" + s + "', ");
}
System.out.println("\nSorted versions");
Arrays.sort(versions, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
String[] firstVersions = o1.split("\\.");
String[] secondVersions = o2.split("\\.");
int length = Math.max(firstVersions.length, secondVersions.length);
for(int i = 0; i < length; i++) {
// normalize the length. If one part is short, we normalize it with zero
int firstVersion = i < firstVersions.length ? Integer.parseInt(firstVersions[i]) : 0;
int secondVersion = i < secondVersions.length ? Integer.parseInt(secondVersions[i]) : 0;
if(firstVersion < secondVersion)
return -1;
if(firstVersion > secondVersion)
return 1;
}
return 0;
}});
for (String s: versions) {
System.out.print("'" + s + "', ");
}
}
}
答案 6 :(得分:0)
使用NSNumericSearch在大多数情况下都有效,但在版本格式不同时会失败;
e.g。比较时
[self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.2"];
它将返回NSOrderedDescending,而它应返回NSOrderedAscending。
请查看我的NSString类别compareToVersion,它可以很好地处理这个问题;
[@"1.2.2.4" compareToVersion:@"1.2.2.5"];
还有一些助手;
[@"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"];
答案 7 :(得分:-1)
来自Apple的文档:
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
// Load resources for iOS 6.1 or earlier
}
else {
// Load resources for iOS 7 or later
}