Swiftでアプリのバージョンチェック

アプリのバージョンチェックを実装するときは、特に何も考えず String.compare: メソッドを使えばいいじゃんと思っていたのですが、 String.compare: だけだと問題がありました。

結論

こんな感じで、 compare:options:. NumericSearch を指定すればOKでした。

extension String {
    static func checkVersion(lhs lhs: String, rhs: String) {
        switch lhs.compare(rhs, options: .NumericSearch) {
        case .OrderedAscending:
            print("lhsの方がrhsよりも小さい")
        case .OrderedSame:
            print("lhsとrhsは等しい")
        case .OrderedDescending:
            print("lhsの方がrhsよりも大きい")
        }
    }
}

問題の確認(検証)

Playground(Swift 2.2)で行いました

/// 互換性のあるバージョン
let conpatible: String = "1.2.7"
/// 最新バージョン
let latest: String = "1.2.1"
/// 現在のバージョン
let version: String = "1.2.10"
extension String {
    static func checkVersion(lhs lhs: String, rhs: String) {
        print("lhs: \(lhs), rhs: \(rhs)")
        switch lhs.compare(rhs) {
        case .OrderedAscending:
            print("lhsの方がrhsよりも小さい")
        case .OrderedSame:
            print("lhsとrhsは等しい")
        case .OrderedDescending:
            print("lhsの方がrhsよりも大きい")
        }
    }
}
print("step.1")
String.checkVersion(lhs: version, rhs: conpatible)
print("\nstep.2")
String.checkVersion(lhs: version, rhs: latest)

結果

step.1
lhs: 1.2.10, rhs: 1.2.7
lhsの方がrhsよりも小さい

step.2
lhs: 1.2.10, rhs: 1.2.1
lhsの方がrhsよりも大きい

step.1で問題が出ています。1.2.10の方が1.2.7よりも小さいという判断になっています。これは1と7で比較されているということですね。想定としては10と7の判定が行われるはずだったのですが。。。

options.NumericSearch を指定することによって"1"と"7"の比較ではなく10と7の比較が行われる様になったので問題が解消されました。

その他

たまたまこの問題に気づきましたが既知の問題というか。同様の記事がすでにネットにはありましたが備忘録として。

あと全然知らなかったんですけど NSOperatingSystemVersion なんてクラスがiOS8からあったんですね。Swiftだと出番はあまり無いかもとは思いますが知っているといつか使えるかもしれない。

NSOperatingSystemVersionについてまとめられている記事