新しいバージョンを確認するためのダイアログ機能を出すなどの処理を追加するにあたって、「Swift バージョン比較」で検索した時に見つかる記事が正しく動作しないので、動作するものを作りました。
2020-11-02 追記
用途が「古いバージョンから新しいバージョンを比較する」という限定的なものだったので間違ったコードが載っていました。
components関数が消えていたのでメンテナンスも兼ねてアップデートしています。
-
1.0
と1.0.1
`-
1.0.1
の方が新しい
-
-
10
と9
-
10
の方が新しい
-
条件は概ねこのような形ですが、NSComparisonResultを使った形だとうまく動作しません。
print("11".compare("10") == .orderedDescending)
-> true (ok)
print("9".compare("8") == .orderedDescending)
-> true (ok)
print("10".compare("9") == .orderedDescending)
-> false (ng)
解決策
正しくバージョンを比較するには「.」で分割し、先頭から順に数値でチェックする必要があります。
extension String {
func compareVersionText(_ target : String) -> Bool{
let v1 = self.split(separator: ".")
let v2 = target.split(separator: ".")
//個数が揃わない場合もあるので、チェックする数は統一する
let count = max(v1.count, v2.count)
for i in 0..<count {
let vv1 = (v1.count > i) ? v1[i] : "0"
let vv2 = (v2.count > i) ? v2[i] : "0"
//数値でチェックする(数値でチェックできないものは0として扱う)
let vv1num = Int(vv1) ?? 0
let vv2num = Int(vv2) ?? 0
//vv2の方が大きい時点で処理を中断
if vv1num < vv2num {
return true
}
//vv1の方が大きい時点で処理を中断
if vv1num > vv2num {
return false
}
}
//最後まで進んだ場合はfalse(バージョンが一致している)
return false
}
}
使い方
if "1.0".compareVersionText("1.0.1") {
print("it's new version")
}
検証用コード
func testPrint(_ expect : Bool, _ target : Bool){
let formated = String(
format: "%@ %@",
arguments: [
(expect) ? "true" : "false",
(target) ? "true" : "false"
]
)
print(formated)
}
testPrint(true, "1.0".compareVersionText("1.0.1"))
testPrint(true, "1.0".compareVersionText("1.1"))
testPrint(true, "1.0.0".compareVersionText("1.0.1"))
testPrint(true, "1.0.0".compareVersionText("1.1.1"))
testPrint(true, "1.0.0".compareVersionText("10.0.0"))
testPrint(true, "8".compareVersionText("10"))
testPrint(true, "8".compareVersionText("10.1"))
testPrint(true, "1.9.0".compareVersionText("1.10.0"))
//先頭がお大きいバージョン
testPrint(true, "1.10.0".compareVersionText("2.0.0"))
testPrint(false, "2.0.0".compareVersionText("1.10.0"))
//同じバージョン
testPrint(false, "1.0".compareVersionText("1.0"))
//一桁テスト
testPrint(false, "10".compareVersionText("9"))
testPrint(false, "100".compareVersionText("99"))
■ 結果
true true
true true
true true
true true
true true
true true
true true
true true
true true
false false
false false
false false
false false