I have two different app version Strings (i.e. "3.0.1" and "3.0.2").
How can compare these using Swift?
I have two different app version Strings (i.e. "3.0.1" and "3.0.2").
How can compare these using Swift?
Ended up having to convert my Strings to NSStrings:
if storeVersion.compare(currentVersion, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending {
println("store version is newer")
}
Swift 3
let currentVersion = "3.0.1"
let storeVersion = "3.0.2"
if storeVersion.compare(currentVersion, options: .numeric) == .orderedDescending {
print("store version is newer")
}
You don't need to cast it as NSString. String object in Swift 3 is just powerful enough to compare versions like below.
let version = "1.0.0"
let targetVersion = "0.5.0"
version.compare(targetVersion, options: .numeric) == .orderedSame // false
version.compare(targetVersion, options: .numeric) == .orderedAscending // false
version.compare(targetVersion, options: .numeric) == .orderedDescending // true
But sample above does not cover versions with extra zeros.(Ex: "1.0.0" & "1.0")
So, I've made all kinds of these extension methods in String to handle version comparison using Swift. It does consider extra zeros I said, quite simple and will work as you expected.
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThan: "99.0.0"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(equalTo: UIDevice.current.systemVersion))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThan: "3.5.99"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThanOrEqualTo: "13.5.99"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThanOrEqualTo: UIDevice.current.systemVersion))
XCTAssertTrue("0.1.1".isVersion(greaterThan: "0.1"))
XCTAssertTrue("0.1.0".isVersion(equalTo: "0.1"))
XCTAssertTrue("10.0.0".isVersion(equalTo: "10"))
XCTAssertTrue("10.0.1".isVersion(equalTo: "10.0.1"))
XCTAssertTrue("5.10.10".isVersion(lessThan: "5.11.5"))
XCTAssertTrue("1.0.0".isVersion(greaterThan: "0.99.100"))
XCTAssertTrue("0.5.3".isVersion(lessThanOrEqualTo: "1.0.0"))
XCTAssertTrue("0.5.29".isVersion(greaterThanOrEqualTo: "0.5.3"))
Just take a look and take all you want in my sample extension repository with no license to care about.
Swift 4+
let current = "1.3"
let appStore = "1.2.9"
let versionCompare = current.compare(appStore, options: .numeric)
if versionCompare == .orderedSame {
print("same version")
} else if versionCompare == .orderedAscending {
// will execute the code here
print("ask user to update")
} else if versionCompare == .orderedDescending {
// execute if current > appStore
print("don't expect happen...")
}
Swift 3 version
let storeVersion = "3.14.10"
let currentVersion = "3.130.10"
extension String {
func versionToInt() -> [Int] {
return self.components(separatedBy: ".")
.map { Int.init($0) ?? 0 }
}
}
//true
storeVersion.versionToInt().lexicographicallyPrecedes(currentVersion.versionToInt())
Swift 2 version compare
let storeVersion = "3.14.10"
let currentVersion = "3.130.10"
extension String {
func versionToInt() -> [Int] {
return self.componentsSeparatedByString(".")
.map {
Int.init($0) ?? 0
}
}
}
// true
storeVersion.versionToInt().lexicographicalCompare(currentVersion.versionToInt())
The following is working for me:
extension String {
static func ==(lhs: String, rhs: String) -> Bool {
return lhs.compare(rhs, options: .numeric) == .orderedSame
}
static func <(lhs: String, rhs: String) -> Bool {
return lhs.compare(rhs, options: .numeric) == .orderedAscending
}
static func <=(lhs: String, rhs: String) -> Bool {
return lhs.compare(rhs, options: .numeric) == .orderedAscending || lhs.compare(rhs, options: .numeric) == .orderedSame
}
static func >(lhs: String, rhs: String) -> Bool {
return lhs.compare(rhs, options: .numeric) == .orderedDescending
}
static func >=(lhs: String, rhs: String) -> Bool {
return lhs.compare(rhs, options: .numeric) == .orderedDescending || lhs.compare(rhs, options: .numeric) == .orderedSame
}
}
"1.2.3" == "1.2.3" // true
"1.2.3" > "1.2.3" // false
"1.2.3" >= "1.2.3" // true
"1.2.3" < "1.2.3" // false
"1.2.3" <= "1.2.3" // true
"3.0.0" >= "3.0.0.1" // false
"3.0.0" > "3.0.0.1" // false
"3.0.0" <= "3.0.0.1" // true
"3.0.0.1" >= "3.0.0.1" // true
"3.0.1.1.1.1" >= "3.0.2" // false
"3.0.15" > "3.0.1.1.1.1" // true
"3.0.10" > "3.0.100.1.1.1" // false
"3.0.1.1.1.3.1.7" == "3.0.1.1.1.3.1" // false
"3.0.1.1.1.3.1.7" > "3.0.1.1.1.3.1" // true
"3.14.10" == "3.130.10" // false
"3.14.10" > "3.130.10" // false
"3.14.10" >= "3.130.10" // false
"3.14.10" < "3.130.10" // true
"3.14.10" <= "3.130.10" // true
I have mixed the Ashok version and DragonCherry:
// MARK: - Version comparison
extension String {
// Modified from the DragonCherry extension - https://github.com/DragonCherry/VersionCompare
private func compare(toVersion targetVersion: String) -> ComparisonResult {
let versionDelimiter = "."
var result: ComparisonResult = .orderedSame
var versionComponents = components(separatedBy: versionDelimiter)
var targetComponents = targetVersion.components(separatedBy: versionDelimiter)
while versionComponents.count < targetComponents.count {
versionComponents.append("0")
}
while targetComponents.count < versionComponents.count {
targetComponents.append("0")
}
for (version, target) in zip(versionComponents, targetComponents) {
result = version.compare(target, options: .numeric)
if result != .orderedSame {
break
}
}
return result
}
func isVersion(equalTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedSame }
func isVersion(greaterThan targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedDescending }
func isVersion(greaterThanOrEqualTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) != .orderedAscending }
func isVersion(lessThan targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedAscending }
func isVersion(lessThanOrEqualTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) != .orderedDescending }
static func ==(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) == .orderedSame }
static func <(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) == .orderedAscending }
static func <=(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) != .orderedDescending }
static func >(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) == .orderedDescending }
static func >=(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) != .orderedAscending }
}
Using:
"1.2.3" == "1.2.3" // true
"1.2.3" > "1.2.3" // false
"1.2.3" >= "1.2.3" // true
"1.2.3" < "1.2.3" // false
"1.2.3" <= "1.2.3" // true
"3.0.0" >= "3.0.0.1" // false
"3.0.0" > "3.0.0.1" // false
"3.0.0" <= "3.0.0.1" // true
"3.0.0.1" >= "3.0.0.1" // true
"3.0.1.1.1.1" >= "3.0.2" // false
"3.0.15" > "3.0.1.1.1.1" // true
"3.0.10" > "3.0.100.1.1.1" // false
"3.0.1.1.1.3.1.7" == "3.0.1.1.1.3.1" // false
"3.0.1.1.1.3.1.7" > "3.0.1.1.1.3.1" // true
"3.14.10" == "3.130.10" // false
"3.14.10" > "3.130.10" // false
"3.14.10" >= "3.130.10" // false
"3.14.10" < "3.130.10" // true
"3.14.10" <= "3.130.10" // true
"0.1.1".isVersion(greaterThan: "0.1")
"0.1.0".isVersion(equalTo: "0.1")
"10.0.0".isVersion(equalTo: "10")
"10.0.1".isVersion(equalTo: "10.0.1")
"5.10.10".isVersion(lessThan: "5.11.5")
"1.0.0".isVersion(greaterThan: "0.99.100")
"0.5.3".isVersion(lessThanOrEqualTo: "1.0.0")
"0.5.29".isVersion(greaterThanOrEqualTo: "0.5.3")
Using Swift 3, application version strings can be compare using the compare function with the option set to numeric.
read this String Programming Guide from Apple Developers' documentation for Objective-C examples of how it works.
i tried these at https://iswift.org/playground
print("2.0.3".compare("2.0.4", options: .numeric))//orderedAscending
print("2.0.3".compare("2.0.5", options: .numeric))//orderedAscending
print("2.0.4".compare("2.0.4", options: .numeric))//orderedSame
print("2.0.4".compare("2.0.3", options: .numeric))//orderedDescending
print("2.0.5".compare("2.0.3", options: .numeric))//orderedDescending
print("2.0.10".compare("2.0.11", options: .numeric))//orderedAscending
print("2.0.10".compare("2.0.20", options: .numeric))//orderedAscending
print("2.0.0".compare("2.0.00", options: .numeric))//orderedSame
print("2.0.00".compare("2.0.0", options: .numeric))//orderedSame
print("2.0.20".compare("2.0.19", options: .numeric))//orderedDescending
print("2.0.99".compare("2.1.0", options: .numeric))//orderedAscending
Hope that helps!
If you like using libraries, use this one, don't reinvent the wheel. https://github.com/zenangst/Versions
Sometimes, the storeVersion's length is not equal to the currentVersion's. e.g. maybe storeVersion is 3.0.0
, however, you fixed a bug and named it 3.0.0.1
.
func ascendingOrSameVersion(minorVersion smallerVersion:String, largerVersion:String)->Bool{
var result = true //default value is equal
let smaller = split(smallerVersion){ $0 == "." }
let larger = split(largerVersion){ $0 == "." }
let maxLength = max(smaller.count, larger.count)
for var i:Int = 0; i < maxLength; i++ {
var s = i < smaller.count ? smaller[i] : "0"
var l = i < larger.count ? larger[i] : "0"
if s != l {
result = s < l
break
}
}
return result
}
You can do it using 'String.compare' method. Use ComparisonResult to identify when your version greater, equal or less.
Example:
"1.1.2".compare("1.1.1").rawValue -> ComparisonResult.orderedDescending
"1.1.2".compare("1.1.2").rawValue -> ComparisonResult.orderedSame
"1.1.2".compare("1.1.3").rawValue -> ComparisonResult.orderedAscending
Wrote a small Swift 3 class to do this:
class VersionString: NSObject {
// MARK: - Properties
var string = ""
override var description: String {
return string
}
// MARK: - Initialization
private override init() {
super.init()
}
convenience init(_ string: String) {
self.init()
self.string = string
}
func compare(_ rhs: VersionString) -> ComparisonResult {
return string.compare(rhs.string, options: .numeric)
}
static func ==(lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.compare(rhs) == .orderedSame
}
static func <(lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.compare(rhs) == .orderedAscending
}
static func <=(lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.compare(rhs) == .orderedAscending || lhs.compare(rhs) == .orderedSame
}
static func >(lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.compare(rhs) == .orderedDescending
}
static func >=(lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.compare(rhs) == .orderedDescending || lhs.compare(rhs) == .orderedSame
}
}
let v1 = VersionString("1.2.3")
let v2 = VersionString("1.2.3")
print("\(v1) == \(v2): \(v1 == v2)") // 1.2.3 == 1.2.3: true
print("\(v1) > \(v2): \(v1 > v2)") // 1.2.3 > 1.2.3: false
print("\(v1) >= \(v2): \(v1 >= v2)") // 1.2.3 >= 1.2.3: true
print("\(v1) < \(v2): \(v1 < v2)") // 1.2.3 < 1.2.3: false
print("\(v1) <= \(v2): \(v1 <= v2)") // 1.2.3 <= 1.2.3: true
@DragonCherry solution is great!
But, unfortunately, it doesn't work when the version is like 1.0.1.2
(I know, it shouldn't exist, but things happens).
I changed your extension and improved the tests to cover (I believe) all cases.
Also, I created an extension that removes all the unnecessary characters from the version string, sometimes it can be v1.0.1.2
.
You can check all the code in the following gists:
Hope it helps anyone :)
I ended up creating below class for my project. Sharing it here, in case it helps someone. Cheers ...!!
import Foundation
final class AppVersionComparator {
var currentVersion: String
init() {
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
self.currentVersion = version ?? ""
}
func compareVersions(lhs: String, rhs: String) -> ComparisonResult {
let comparisonResult = lhs.compare(rhs, options: .numeric)
return comparisonResult
}
/**
- If lower bound is present perform lowerBound check
- If upper bound is present perform upperBound check
- Return true if both are nil
*/
func fallsInClosedRange(lowerBound: String?, upperBound: String?) -> Bool {
if let lowerBound = lowerBound {
let lowerBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: lowerBound)
guard lowerBoundComparisonResult == .orderedSame || lowerBoundComparisonResult == .orderedDescending else { return false }
}
if let upperBound = upperBound {
let upperBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: upperBound)
guard upperBoundComparisonResult == .orderedSame || upperBoundComparisonResult == .orderedAscending else { return false }
}
return true
}
/**
- If lower bound is present perform lowerBound check
- If upper bound is present perform upperBound check
- Return true if both are nil
*/
func fallsInOpenRange(lowerBound: String?, upperBound: String?) -> Bool {
if let lowerBound = lowerBound {
let lowerBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: lowerBound)
guard lowerBoundComparisonResult == .orderedDescending else { return false }
}
if let upperBound = upperBound {
let upperBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: upperBound)
guard upperBoundComparisonResult == .orderedAscending else { return false }
}
return true
}
func isCurrentVersionGreaterThan(version: String) -> Bool {
let result = compareVersions(lhs: currentVersion, rhs: version)
return result == .orderedDescending
}
func isCurrentVersionLessThan(version: String) -> Bool {
let result = compareVersions(lhs: currentVersion, rhs: version)
return result == .orderedAscending
}
func isCurrentVersionEqualsTo(version: String) -> Bool {
let result = compareVersions(lhs: currentVersion, rhs: version)
return result == .orderedSame
}}
Some test cases too:
import XCTest
class AppVersionComparatorTests: XCTestCase {
var appVersionComparator: AppVersionComparator!
override func setUp() {
super.setUp()
self.appVersionComparator = AppVersionComparator()
}
func testInit() {
XCTAssertFalse(appVersionComparator.currentVersion.isEmpty)
}
func testCompareEqualVersions() {
let testVersions = [VersionComparisonModel(lhs: "1.2.1", rhs: "1.2.1"),
VersionComparisonModel(lhs: "1.0", rhs: "1.0"),
VersionComparisonModel(lhs: "1.0.2", rhs: "1.0.2"),
VersionComparisonModel(lhs: "0.1.1", rhs: "0.1.1"),
VersionComparisonModel(lhs: "3.2.1", rhs: "3.2.1")]
for model in testVersions {
let result = appVersionComparator.compareVersions(lhs: model.lhs, rhs: model.rhs)
XCTAssertEqual(result, .orderedSame)
}
}
func testLHSLessThanRHS() {
let lhs = "1.2.0"
let rhs = "1.2.1"
let result = appVersionComparator.compareVersions(lhs: lhs, rhs: rhs)
XCTAssertEqual(result, .orderedAscending)
}
func testInvalidRange() {
let isCurrentVersionInClosedRange = appVersionComparator.currentVersionFallsInClosedRange(lowerBound: "", upperBound: "")
XCTAssertFalse(isCurrentVersionInClosedRange)
let isCurrentVersionInOpenRange = appVersionComparator.currentVersionFallsInOpenRange(lowerBound: "", upperBound: "")
XCTAssertFalse(isCurrentVersionInOpenRange)
}
func testCurrentInClosedRangeSuccess() {
appVersionComparator.currentVersion = "1.2.1"
let isCurrentVersionInClosedRange = appVersionComparator.currentVersionFallsInClosedRange(lowerBound: "1.2.0", upperBound: "1.2.1")
XCTAssert(isCurrentVersionInClosedRange)
}
func testIsCurrentVersionGreaterThanGivenVersion() {
appVersionComparator.currentVersion = "1.4.2"
let result = appVersionComparator.isCurrentVersionGreaterThan(version: "1.2")
XCTAssert(result)
}
func testIsCurrentVersionLessThanGivenVersion() {
appVersionComparator.currentVersion = "1.4.2"
let result = appVersionComparator.isCurrentVersionLessThan(version: "1.5")
XCTAssert(result)
}
func testIsCurrentVersionEqualsToGivenVersion() {
appVersionComparator.currentVersion = "1.4.2"
let result = appVersionComparator.isCurrentVersionEqualsTo(version: "1.4.2")
XCTAssert(result)
}}
Mock Model:
struct VersionComparisonModel {
let lhs: String
let rhs: String
}
Your use of NSString
is the right way to go, but here is a non-Foundation attempt for fun:
let storeVersion = "3.14.10"
let currentVersion = "3.130.10"
func versionToArray(version: String) -> [Int] {
return split(version) {
$0 == "."
}.map {
// possibly smarter ways to do this
$0.toInt() ?? 0
}
}
storeVersion < currentVersion // false
// true
lexicographicalCompare(versionToArray(storeVersion), versionToArray(currentVersion))
extension String {
func compareVersionNumbers(other: String) -> Int {
let nums1 = self.split(separator: ".").map({ Int($0) ?? 0 })
let nums2 = other.split(separator: ".").map({ Int($0) ?? 0 })
for i in 0..<max(nums1.count, nums2.count) {
let num1 = i < nums1.count ? nums1[i] : 0
let num2 = i < nums2.count ? nums2[i] : 0
if num1 != num2 {
return num1 - num2
}
}
return 0
}
}
Here is a simple swift struct
public struct VersionString: Comparable {
public let rawValue: String
public init(_ rawValue: String) {
self.rawValue = rawValue
}
public static func == (lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.rawValue.compare(rhs.rawValue, options: .numeric) == .orderedSame
}
public static func < (lhs: VersionString, rhs: VersionString) -> Bool {
return lhs.rawValue.compare(rhs.rawValue, options: .numeric) == .orderedAscending
}
}
I can understand there are many good answers given. Here is my version of comparison of app version.
func compareVersions(installVersion: String, storeVersion: String) -> Bool{
// 1.7.5
var installedArr = installVersion.components(separatedBy: ".")
var storeArr = storeVersion.components(separatedBy: ".")
var isAvailable = false
while(installedArr.count < storeArr.count){
installedArr.append("0")
}
while(storeArr.count < installedArr.count){
storeArr.append("0")
}
for index in 0 ..< installedArr.count{
if let storeIndex=storeArr[index].toInt(), let installIndex=installedArr[index].toInt(){
if storeIndex > installIndex{
isAvailable = true
return isAvailable
}
}
}
return isAvailable
}
Here is my effort to cover all cases of version formats like compare "10.0"
with "10.0.1"
, let me know if I have missed any case.
Here is the gist https://gist.github.com/shamzahasan88/bc22af2b7c96b6a06a064243a02c8bcc. Hope it helps everyone.
And here is the code if anyone don't want to rate my gist :P
extension String {
// Version format "12.34.39" where "12" is "Major", "34" is "Minor" and "39" is "Bug fixes"
// "maximumDigitCountInVersionComponent" is optional parameter determines the maximum length of "Maajor", "Minor" and "Bug Fixes"
func shouldUpdateAsCompareToVersion(storeVersion: String, maximumDigitCountInVersionComponent: Int = 5) -> Bool {
let adjustTralingZeros: (String, Int)->String = { val, count in
return "\(val)\((0..<(count)).map{_ in "0"}.joined(separator: ""))"
}
let adjustLength: ([String.SubSequence], Int)->[String] = { strArray, count in
return strArray.map {adjustTralingZeros("\($0)", count-$0.count)}
}
let storeVersionSubSequence = storeVersion.split(separator: ".")
let currentVersionSubSequence = self.split(separator: ".")
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = maximumDigitCountInVersionComponent
formatter.maximumIntegerDigits = maximumDigitCountInVersionComponent
let storeVersions = adjustLength(storeVersionSubSequence, maximumDigitCountInVersionComponent)
let currentVersions = adjustLength(currentVersionSubSequence, maximumDigitCountInVersionComponent)
var storeVersionString = storeVersions.joined(separator: "")
var currentVersionString = currentVersions.joined(separator: "")
let diff = storeVersionString.count - currentVersionString.count
if diff > 0 {
currentVersionString = adjustTralingZeros(currentVersionString, diff)
}else if diff < 0 {
storeVersionString = adjustTralingZeros(storeVersionString, -diff)
}
let literalStoreVersion = Int(storeVersionString)!
let literalCurrentVersion = Int(currentVersionString)!
return literalCurrentVersion < literalStoreVersion
}
}
Usage:
print("33.29".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // true
print("35.29".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // false
print("34.23.2".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // false
print("34.23.18".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // true
extension String {
func versionCompare(_ otherVersion: String) -> ComparisonResult {
let versionDelimiter = "."
var versionComponents = self.components(separatedBy: versionDelimiter) // <1>
var otherVersionComponents = otherVersion.components(separatedBy: versionDelimiter)
let zeroDiff = versionComponents.count - otherVersionComponents.count // <2>
if zeroDiff == 0 { // <3>
// Same format, compare normally
return self.compare(otherVersion, options: .literal)
} else {
let zeros = Array(repeating: "0", count: abs(zeroDiff)) // <4>
if zeroDiff > 0 {
otherVersionComponents.append(contentsOf: zeros) // <5>
} else {
versionComponents.append(contentsOf: zeros)
}
return versionComponents.joined(separator: versionDelimiter)
.compare(otherVersionComponents.joined(separator: versionDelimiter), options: .literal) // <6>
}
}
}
//USAGE
let previousVersionNumber = "1.102.130"
let newAnpStoreVersion = "1.2" // <- Higher
switch previousVersionNumber.versionCompare(newAnpStoreVersion) {
case .orderedAscending:
case .orderedSame:
case .orderedDescending:
}
Once you remove the dots from the version strings, it's a simple Int comparison.
Assumption/Caveat: Version String is always the same number of digits (this fails, if for instance, there is version 1.10.0 since it will be converted to 1110 and version 2.1.0 will be compared as 210). It's not a huge leap to do a comparison of major first, then minor, then patch or incorporate other strategies mentioned in other answers and combine.
// inner json (there are *many* more parameters, but this is the only one we're concerned with)
struct AppUpdateData: Codable {
let version: String
}
// outer json
struct AppVersionResults: Codable {
let results: [AppUpdateData]
}
struct AppVersionComparison {
let currentVersion: Int
let latestVersion: Int
var needsUpdate: Bool {
currentVersion < latestVersion
}
}
// this isn't really doing much for error handling, could just return an optional
func needsUpdate() async throws -> AppVersionComparison {
let bundleId = "com.my.bundleId"
let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleId)")!
let (data, _) = try await URLSession.shared.data(from: url)
let noResultsError: NSError = NSError(domain: #function, code: 999, userInfo: [NSLocalizedDescriptionKey: "No results"])
do {
let decoder = JSONDecoder()
let decoded = try decoder.decode(AppVersionResults.self, from: data)
guard decoded.results.count > 0 else { throw noResultsError }
var latestVersionString = decoded.results[0].version
latestVersionString.removeAll { $0 == "." }
guard let latestVersion = Int(latestVersionString),
var currentVersionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
else { throw noResultsError }
currentVersionString.removeAll { $0 == "." }
guard let currentVersion = Int(currentVersionString) else {
throw noResultsError
}
return .init(currentVersion: currentVersion, latestVersion: latestVersion)
}
}
How about this:
class func compareVersion(_ ver: String, to toVer: String) -> ComparisonResult {
var ary0 = ver.components(separatedBy: ".").map({ return Int($0) ?? 0 })
var ary1 = toVer.components(separatedBy: ".").map({ return Int($0) ?? 0 })
while ary0.count < 3 {
ary0.append(0)
}
while ary1.count < 3 {
ary1.append(0)
}
let des0 = ary0[0...2].description
let des1 = ary1[0...2].description
return des0.compare(des1, options: .numeric)
}
and test:
func test_compare_version() {
XCTAssertEqual(compareVersion("1.0.0", to: "1.0.0"), .orderedSame)
XCTAssertEqual(compareVersion("1.0.0", to: "1.0."), .orderedSame)
XCTAssertEqual(compareVersion("1.0.0", to: "1.0"), .orderedSame)
XCTAssertEqual(compareVersion("1.0.0", to: "1."), .orderedSame)
XCTAssertEqual(compareVersion("1.0.0", to: "1"), .orderedSame)
XCTAssertEqual(compareVersion("1.0.0", to: "1.0.1"), .orderedAscending)
XCTAssertEqual(compareVersion("1.0.0", to: "1.1."), .orderedAscending)
XCTAssertEqual(compareVersion("1.0.0", to: "1.1"), .orderedAscending)
XCTAssertEqual(compareVersion("1.0.0", to: "2."), .orderedAscending)
XCTAssertEqual(compareVersion("1.0.0", to: "2"), .orderedAscending)
XCTAssertEqual(compareVersion("1.0.0", to: "1.0.0"), .orderedSame)
XCTAssertEqual(compareVersion("1.0.", to: "1.0.0"), .orderedSame)
XCTAssertEqual(compareVersion("1.0", to: "1.0.0"), .orderedSame)
XCTAssertEqual(compareVersion("1.", to: "1.0.0"), .orderedSame)
XCTAssertEqual(compareVersion("1", to: "1.0.0"), .orderedSame)
XCTAssertEqual(compareVersion("1.0.1", to: "1.0.0"), .orderedDescending)
XCTAssertEqual(compareVersion("1.1.", to: "1.0.0"), .orderedDescending)
XCTAssertEqual(compareVersion("1.1", to: "1.0.0"), .orderedDescending)
XCTAssertEqual(compareVersion("2.", to: "1.0.0"), .orderedDescending)
XCTAssertEqual(compareVersion("2", to: "1.0.0"), .orderedDescending)
XCTAssertEqual(compareVersion("1.0.0", to: "0.9.9"), .orderedDescending)
XCTAssertEqual(compareVersion("1.0.0", to: "0.9."), .orderedDescending)
XCTAssertEqual(compareVersion("1.0.0", to: "0.9"), .orderedDescending)
XCTAssertEqual(compareVersion("1.0.0", to: "0."), .orderedDescending)
XCTAssertEqual(compareVersion("1.0.0", to: "0"), .orderedDescending)
XCTAssertEqual(compareVersion("", to: "0"), .orderedSame)
XCTAssertEqual(compareVersion("0", to: ""), .orderedSame)
XCTAssertEqual(compareVersion("", to: "1"), .orderedAscending)
XCTAssertEqual(compareVersion("1", to: ""), .orderedDescending)
XCTAssertEqual(compareVersion("1.0.0", to: "1.0.0.9"), .orderedSame)
XCTAssertEqual(compareVersion("1.0.0.9", to: "1.0.0"), .orderedSame)
}