Note — This article is now outdated. There’s a new article with updated info here.
When working on a project not too long ago, My teammate and I came across the following situation.
We started developing the project on Swift 2.0 and moved over to 2.1 with the released of Xcode 7.1. We used a class conforming to the NSCoding
protocol to store the basic information about the app’s user. Among the many details stored of the user, one particular detail is an array of Swift structure instances. We used this to store details about the user’s social connections. And, this property was an optional. We wrote the required boilerplate archiving and unarchiving code to the class and it was all set. We forgot about the class and moved on to other things in the project. We realised that the class wasn’t archiving the swift structure instances only after a while. After a bit of digging, we learnt that structure instances aren’t convertible to AnyObject. And, since that property was an optional, it wasn’t leading to any crashes when unarchiving, instead it just gave out a nil value.
The following is an example I wrote for this article, recreating a similar situation.
Here, the structure Connections
contains basic information about a user’s social connections. The class ProfileDetails
has the property connections
which is an array of the said structure. The static method getProfileDetails()
gives an instance of the same class after unarchiving. The method saveProfileDetails()
sets the modified property values and archives class object to file with the modifications preserved.
The problem we encountered was when assigning an array of Connections
instances to the connections
property, it threw no error and everything was merry. Except, when accessing connections
property later on always gave a nil
value.
This happened because structure instances cannot be represented as AnyObject
, which is quite obvious when you know AnyObject
is only for class instances. And, the swift type Any
(which supports structure instances) is not accepted in the encodeObject:forKey:
method.
The workaround we used was to introduce a class similar to the structure and convert the array of structure instances to that class’s objects just before archiving. And doing the opposite when unarchiving. We did this instead of just using the class because we needed a value type for that property in our project.
Thank you Karthik Mitta.