У меня есть две разные строки версии приложения (т.е. "3.0.1" и "3.0.2" ).
Как сравнить их с помощью Swift?
У меня есть две разные строки версии приложения (т.е. "3.0.1" и "3.0.2" ).
Как сравнить их с помощью Swift?
Закончилось преобразовать мои строки в 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")
}
Вам не нужно указывать его как NSString. Объект String в Swift 3 достаточно мощный, чтобы сравнивать версии, как показано ниже.
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
Но пример выше не охватывает версии с дополнительными нулями. (Пример: "1.0.0" и "1.0" )
Итак, я использовал все виды этих методов расширения в String для обработки сравнения версий с помощью Swift. Он считает, что дополнительные нули, которые я сказал, довольно просты и будут работать так, как вы ожидали.
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"))
Просто взгляните и возьмите все, что захотите, в моем репозитории расширения без лицензии, чтобы заботиться о нем.
версия Swift 3
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
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())
Следующее работает для меня:
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
Иногда длина storeVersion не равна currentVersion. например возможно, storeVersion 3.0.0
, однако вы исправили ошибку и назвали ее 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
}
Используя Swift 3, строки версии приложения можно сравнить с помощью функции сравнения с опцией, установленной на числовую.
прочитайте это руководство по программированию строк от документации разработчиков Apple для Objective-C примеров того, как это работает.
Я пробовал их на 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
Надеюсь, что это поможет!
Если вам нравится использовать библиотеки, используйте этот, не изобретайте колесо. https://github.com/zenangst/Versions
Вы можете сделать это, используя метод String.compare. Используйте ComparisonResult, чтобы определить, когда ваша версия больше, равна или меньше.
Пример:
"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
Написал небольшой класс Swift 3 для этого:
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
Ваше использование NSString
- это правильный путь, но вот попытка не-Foundation для развлечения:
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))
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...")
}
Вот простая быстрая структура
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
}
}
Как насчет этого:
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)
}
и проверить:
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)
}
Решение @DragonCherry великолепно!
Но, к сожалению, он не работает, когда версия похожа на 1.0.1.2
(я знаю, она должна существовать, но вещи случаются).
Я изменил ваше расширение и улучшил тесты, чтобы охватить (я считаю) все случаи. Кроме того, я создал расширение, которое удаляет все ненужные символы из строки версии, иногда это может быть v1.0.1.2
.
Вы можете проверить весь код в следующих списках:
Надеюсь, это кому-нибудь поможет :)