How do I add properties to a class when I update my app when users already have created class instances?

I have an app where users create a "Worker" object defined by my Worker class. I want to add some additional properties to this Worker class in an update (date of hire, jobs completed, etc.). How can my current users utilize these new properties with their older Worker class instances. All new Workers of course have the new properties available but the old ones seem to be left out since they were created before the update. Is this possible? I have searched and I don't know if extensions or something else could work since my new properties are stored.


My data is being stored using NSCoding. The problem is when I update my app with the new class properties, class instances created before the update don't get the new properties. In other words, to have access to the new class properties do users HAVE to create a new class instance. If so then how do you add features to existing apps?.

Accepted Reply

If I catch your point exactly, I feel you are mixing 2 different things :

- the data stored on a file (using NSCoding) : it is visible to the users : it's users' business

- the instances your app create : they cannot be "manipulated" by users, it's your app business


So if you want to add a new property tou your class, your are free to do it.

Question is : what about existing users' data.


This was for OSX App, but should be very similar for IOS.


For the following, let's assume you have defined a new property in the class:

var newProperty: Bool

the key for coding is

let newPropertyKey = "newpropertyKey"


What you have to do in the new release:

1. In required init(coder decoder: NSCoder), add the decoding for the new property.

Here you need to take care and test for the following :

- once data have been saved with the new version, everything is OK

- but first time you read data created by the old version, the field for the key does not exist yet.

You need also to take care wether the field was created with Swift 2 version of Swift 3.


Here is how I handle it (Swift3)


    required init(coder decoder: NSCoder) {

        if decoder.containsValue(forKey: newPropertyKey) {     // is it already stored ?
            self.newProperty = decoder.decodeObject(forKey: newPropertyKey) as? Bool ?? decoder.decodeBool(forKey: newPropertyKey)
               // was it created as an object (in Swift2) or as a Bool (in Swift3)

        } else {    // not yet saved ; will be created at next encode
            self.newProperty = false // or true if you decide so
        }
     }


2. In encode(with coder: NSCoder), you simply add the new p^roperty


    func encode(with coder: NSCoder) {
        // encode all previous properties
        coder.encode(self.newProperty, forKey: newPropertyKey)       // the new one
          // Note that if newPropoerty is optional (Bool?), you need to encode newPropertyKey!
    }
}


3. Of course handle code to handle the new property.

Replies

If I catch your point exactly, I feel you are mixing 2 different things :

- the data stored on a file (using NSCoding) : it is visible to the users : it's users' business

- the instances your app create : they cannot be "manipulated" by users, it's your app business


So if you want to add a new property tou your class, your are free to do it.

Question is : what about existing users' data.


This was for OSX App, but should be very similar for IOS.


For the following, let's assume you have defined a new property in the class:

var newProperty: Bool

the key for coding is

let newPropertyKey = "newpropertyKey"


What you have to do in the new release:

1. In required init(coder decoder: NSCoder), add the decoding for the new property.

Here you need to take care and test for the following :

- once data have been saved with the new version, everything is OK

- but first time you read data created by the old version, the field for the key does not exist yet.

You need also to take care wether the field was created with Swift 2 version of Swift 3.


Here is how I handle it (Swift3)


    required init(coder decoder: NSCoder) {

        if decoder.containsValue(forKey: newPropertyKey) {     // is it already stored ?
            self.newProperty = decoder.decodeObject(forKey: newPropertyKey) as? Bool ?? decoder.decodeBool(forKey: newPropertyKey)
               // was it created as an object (in Swift2) or as a Bool (in Swift3)

        } else {    // not yet saved ; will be created at next encode
            self.newProperty = false // or true if you decide so
        }
     }


2. In encode(with coder: NSCoder), you simply add the new p^roperty


    func encode(with coder: NSCoder) {
        // encode all previous properties
        coder.encode(self.newProperty, forKey: newPropertyKey)       // the new one
          // Note that if newPropoerty is optional (Bool?), you need to encode newPropertyKey!
    }
}


3. Of course handle code to handle the new property.

Thank you for the insight. I didn't think it could be a problem with NSCoding. Unfortunately I won't be able to try out the new code until later this weekend.

let us know once you have tested.


good luck.

Yes this seems to solve my issue. Thank you for your help.