So, this is my last post in this series about linked lists. There is one last thing we have to add: serialising for storing our linked list on disk or sending over a network. As you have seen in this post, serialising has become much easier in Swift 4. If we make the requirement that our generic class T is already Codable the rest is quite easy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public class Node<T> where T: Codable { typealias NodeType = Node<T> // just to shorten definitions … } … public struct LinkedListIterator<T>: IteratorProtocol where T: Codable { // let's create an iterator for our linked list public typealias Element = Node<T> // the type of each node in the list … } … enum CodingError: Error { // enum for coding errors case decoding(String) } public class LinkedList<T>: Sequence, Codable where T: Codable { // the linked list, finally, conforming to the sequence and the codable protocol … private enum CodingKeys: String, CodingKey { // the keys for the coders are not simple strings anymore case List // but enums of Strings (or Ints) } public required init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) // get the container from the decoder if let list = try? values.decode([T].self, forKey: .List) { // and decode the array for object in list { // iterate over all elements self.append(value: object) // and append it to our list } } else { throw CodingError.decoding("Decoding Error: \(dump(values))") // had no success } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) // get an empty container first var next = head // start at the top var list = [T]() // create an array of the objects while next != nil { // iterate over the whole list list.append(next!.value) // and append our objects next = next!.next // get the next item } try container.encode(list, forKey: .List) // and encode the list } … |
In all our classes using generics we have to add the constraint of T conforming to the Codable protocol. If T wouldn’t be Codable encoding of our linked list would fail. As mentioned in the previous post the encoding and decoding methods may throw exceptions. So, I have defined an enum for the possible coding error. And we have to define an enum for the coding keys, in our case only with one key. That’s it for the preparation. Now let’s look at the actual encoding part first:
First we have to get an empty container. And then I make our life easy; I just copy our linked list to an array of T and let the encoder encode that. Since Swift knows how to encode collections we’re done already. Simple, isn’t it?
And the decoding part is just the other way round. It’s implemented in another init which gets a decoder. We’ll take the container and let it decode to the array of T. We have to take care if this fails. If everything’s ok we just loop over the array and append the items to our linked list. That’s it.
Now we can test the serialisation of our linked list:
1 2 3 4 5 6 7 |
let stringArray = ["1. item", "2. item", "3. item"] let mySecondList = LinkedList<String>(stringArray) Swift.print("The second list: \(mySecondList.description)") let data = try PropertyListEncoder().encode(mySecondList) let myDecodedList = try PropertyListDecoder().decode(LinkedList<String>.self, from: data) Swift.print("The decoded list: \(myDecodedList.description)") |
We create a linked list from an array and let it encode by the PropertyListEncoder. The resulting data object we give to a PropertyListDecoder and let it decode to a linked list of strings. Everything works fine:
1 2 |
The second list: [1. item, 2. item, 3. item] The decoded list: [1. item, 2. item, 3. item] |
This was my final post on linked lists in Swift. I hope you’ve enjoyed it. Here is the playground with all the classes and methods.