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.

Reference

  1. http://blog.scottlogic.com/2014/09/24/swift-anyobject.html