0

Sometimes cache cleanup is needed after a big update, so I'd like to check once the user updates the app if the app version is above or below the one that needs cache cleanup.

For example, I currently have this to check when it's a new app update or install:

import BundleInfoVersioning

func displayUpdateNotification() {
    let bundleInfoVersioning = BundleInfoVersioning(bundle: .main)
    
    bundleInfoVersioning.check(forKeyPath: "CFBundleShortVersionString") { (old: String? , newVersion: String?) in
        if old == nil {
            // You can place some analytics here ...
            print(" New App Installed")
        }
        else {
            // You can place some analytics here ...
            print(" New App Update")
            if(showUpdate) {
                self.shouldShowUpdatePopUp = true
            }
        }
    }
}

So if the user does an app update compare the installed version with the version defined by me that needs cache cleanup, how can I compare that string with the new version? Like:

if after update the user is in version 2.5.2 or below, clean cache once

Arturo
  • 3,254
  • 2
  • 22
  • 61

1 Answers1

1

So, I had a similar issue some time back, we needed to be able to compare the installed version with cloud based information and do "things"

The first thing I did was built a concept of a "version", which is based on "major.minor.patch" and "build" properties.

This allowed the cloud to send us a structure which we could understand.

struct Version: Comparable, CustomStringConvertible {
    
    let major: Int
    let minor: Int
    let patch: Int
    
    let build: Int
    
    init(major: Int, minor: Int, patch: Int, build: Int) {
        self.major = major
        self.minor = minor
        self.patch = patch
        self.build = build
    }
    
    init(from: String, build: String = "0")  {
        let buildNumber = Int(build) ?? 0
        let parts = from.split(separator: ".")
        let major = Int(parts[0]) ?? 0
        var minor = 0
        var patch = 0
        if parts.count >= 2 {
            minor = Int(parts[1]) ?? 0
        }
        if parts.count >= 3 {
            patch = Int(parts[2]) ?? 0
        }
        
        self.init(major: major, minor: minor, patch: patch, build: buildNumber)
    }
    
    var description: String {
        return String(format: "%02d.%02d.%02d build %02d", major, minor, patch, build)
    }
    

    static func <(lhs: Version, rhs: Version) -> Bool {
        return lhs.description.compare(rhs.description, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
    }

    static func ==(lhs: Version, rhs: Version) -> Bool {
        return lhs.description.compare(rhs.description, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedSame
    }

}

Add in a simple extensions to get it from the app itself...

extension Version {
    
    static var app: Version = {
        let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
        let build = Bundle.main.infoDictionary!["CFBundleVersion"] as! String
        return Version(from: version, build: build)
    }()
    
}

And then you can do things like

if Version.app == Version(from: "2.5.2") {
    // And now do some stuff
}

Now, you will need to play around with this, as my needs might not be exactly the same as yours, but this is basically what I was able to use and it worked well, for my needs

But aren't you comparing 2 strings there? What if the user is in version 3.0.0 and I want all users with version 2.5.2 and below to clean cache? Can I do: if Version.app <= Version(from: "2.5.2") { } ?

This is one of those nice little features of Swift (actually ObjC ). Have a look at what NSString.CompareOptions.numeric does for the comparison

For example...

let userVersion = Version(from: "3.0.0")
let targetVersion = Version(from: "2.5.2")

userVersion == targetVersion // 3.0.0 == 2.5.2 - false ✅
userVersion > targetVersion // 3.0.0 > 2.5.2 - true ✅
userVersion < targetVersion // 3.0.0 < 2.5.2 - false ✅
userVersion >= targetVersion // 3.0.0 >= 2.5.2 - true ✅
userVersion <= targetVersion // 3.0.0 <= 2.5.2 - false ✅
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • But aren't you comparing 2 strings there? What if the user is in version `3.0.0` and I want all users with version `2.5.2` and below to clean cache? Can I do: `if Version.app <= Version(from: "2.5.2") { }` ? – Arturo Feb 03 '22 at 00:13
  • @Arturo You'd think so wouldn't you, but do some research into `NSString.CompareOptions.numeric` – MadProgrammer Feb 03 '22 at 00:14
  • @Arturo [This](https://stackoverflow.com/questions/27932408/compare-two-version-strings-in-swift/27932531) is probably where I stole ... I mean learnt it from – MadProgrammer Feb 03 '22 at 00:20
  • It looks good, I'm testing it and thanks for the link, I'm looking at it too – Arturo Feb 03 '22 at 00:21
  • We used this concept in production to ensure that the user could only use supported versions of the app. Versions below the supported version, from the cloud, would lock the user out of the app. If a new version was available (but the version was still supported), they'd get an upgrade prompt – MadProgrammer Feb 03 '22 at 00:24
  • That is actually another feature I have to implement so this comes very very handy – Arturo Feb 03 '22 at 00:25
  • 1
    @Arturo For me, the point was to get a "abstract" concept of the version which was independent of the cloud and the app, so I could then bind them together, because the cloud always has a different concept of how these things should be represented – MadProgrammer Feb 03 '22 at 00:28
  • @MadProgrammer no need to implement all the operators when conforming to Comparable. You just need to implement less than and equal to operators. All the rest is automatically synthesized for you. **Conforming to the Comparable Protocol Types with Comparable conformance implement the less-than operator (<) and the equal-to operator (==). These two operations impose a strict total order on the values of a type, in which exactly one of the following must be true for any two values a and b:** – Leo Dabus Feb 03 '22 at 00:34
  • @LeoDabus I think that's what I had originally, I just went overboard – MadProgrammer Feb 03 '22 at 00:36