Persistent reusable container for item collections in Swift
Let’s build a container where we can store collections of items conforming to a protocol. All the collections are identified by a case in enum. For making the container reusable, we’ll use protocols as requirements on keys and items in collections. Moreover, the container should be archivable and unarchivable.
Creating a reusable container
Container’s implementation wraps a dictionary and adds methods for conveniently adding an item for key. Key must implement Hashable and RawRepresentable: then it can be used in Dictionary and converting it to representation suitable for storing on disk.
Every item needs to implement ContainerItem protocol what requires to implement methods used when archiving and unarchiving the item. Thanks to Codable protocol in Swift, it is very simple to transform the item to data and back. ContainerItem provides default implementations for its own methods when the type is conforming to Codable. Therefore, when some type wants to implement ContainerItem, then it only needs to conform to ContainerItem and Codable and default implementations will do the rest.
Archiving and unarchiving the container and it’s content
Let’s first extend the container with write method. As enum cases are used as keys in dictionary, then let’s implement write method for enums what have String as RawValue. (what should be a preferred way in this use case as its provides the most readable representation of the key). We can then map dictionary entries so that key is converted to String and value to array of JSON data objects. NSKeyedArchiver provides a simple way of storing Dictionary with archivable types (like String and array of Data).
For initialising the container from data on disk, we need to make sure that we convert JSON data back to the correct type. Therefore we can extend the container for this specific enum case and converting data back to the correct type. When using enums it is easy to switch over the possible cases and then converting list of data objects to list of known types.
Wrapping dictionary with another type can be useful inmany cases where we have a known list of keys. Specialising generic types is an efficient way of adding more features to it and keeping type information intact. Thanks to Codable protocol we were able to make types archivable and unarchivable.
PersistentGenericContainer (Xcode 11.1)