FileManager extension for PropertyListEncoder

Alexei Kozachenko
2 min readNov 16, 2018

--

Continuing with SwifterSwift

After adding two FileManager extension methods to encode/decode objects using JSON encoder, i was asked to make counterparts (encoder and decoder) for PropertyListEncoder.

Both encoders have same methods for encoding & decoding, which means I was able to use the same logic, doing minimum changes to implement new methods.

So I decided to start with an encoder. Just like JSONEncoder, PropertyListEncoder requires an object that conforms to Encodable(or Codable) protocol in order to be able to encode it.

The encode method of the encoder returns and object of type Data which is exactly what FileManager needs in order to create a file using createFile method.

So the code would look something like this:

let data = try encoder.encode(object)FileManager.default.createFile(atPath: url.path, contents: data, attributes: nil)

I implemented a generic extension method for FileManager encodePlist as:

public func encodePlist<T: Encodable>(_ object: T, using encoder:PropertyListEncoder=PropertyListEncoder(), to url: URL, attributes: [FileAttributeKey:Any]? = nil) throws {   let data = try encoder.encode(object)   FileManager.default.createFile(atPath: url.path, contents: data, attributes: nil)}

Unit test for this method would need to test the next:

  • make sure that the extension method does not throw an error
  • check if the file was created at a given url
  • get data back from file
  • decode data to the data type (same data type)
  • check if original data object is the same as decoded object
  • remove the file
func testEncodePlist() {let point = CGPoint(x: 1.1, y: 2.2)let temporaryDirectoryURL = FileManager.default.temporaryDirectorylet temporaryFilename = ProcessInfo().globallyUniqueStringlet fileURL = temporaryDirectoryURL.appendingPathComponent(temporaryFilename)do {   try FileManager.default.encodePlist(point, to: fileURL)   XCTAssert(FileManager.default.fileExists(atPath: fileURL.path))   let data = FileManager.default.contents(atPath: fileURL.path)   XCTAssertNotNil(data)   let decoder = PropertyListDecoder()   let decodedPoint = try decoder.decode(CGPoint.self, from: data!)   XCTAssert(decodedPoint == point)   try FileManager.default.removeItem(at: fileURL)} catch {   XCTFail(error.localizedDescription)}

Initially I implemented encodePlist as encode. But since new method for encoding using PropertyListEncoder had the same signature as the encodemethod with JSONEncoder, I need to make some changes.

I renamed both methods to reflect the encoder name in the name of the function. So for PropertyListEncoder the function was renamed as enodePlist. And the method that I created before was renamed to encodeJSON.

--

--

Alexei Kozachenko

Computer programming and Analysis student at Seneca College.