AckeeCZ/ACKategories

`UserDefault` property wrapper doesn't work on iOS 12

Closed this issue · 0 comments

On iOS 12 and lower, it is not supported to encode primitive values (such as String, Int or Codable objects that encode to single value using singleValueContainer) using JSONEncoder, this means that referenced line, where Encodable object is encoded, throws an error which is ignored.

So if I use code

final class Storage {
    @UserDefault("key", default: nil)
    var version: String?
}

let storage = Storage()
storage.version = "2.7.0"

Following error is thrown on iOS 12.4.1:

Swift.EncodingError.invalidValue(Optional("2.7.0"), Swift.EncodingError.Context(codingPath: [], debugDescription: "Top-level Optional<String> encoded as string JSON fragment.", underlyingError: nil))

This issue will remain present in old systems ➡️ https://bugs.swift.org/browse/SR-6163

I can think of multiple solutions:

  • use different encoder/decoder than JSON - we would have to implement it as PropertyList causes the same issue which is probably too much work
  • constraint our implementation for iOS 13+ as we might be able to check for supported types in UserDefaults but we will never catch cases when Codable object uses custom encode, that encodes object to singleValueContainer
  • we could wrap the encoded value to Array or Dictionary (probably array would be better) so the encoder always has a root object

let data = try? encoder.encode(newValue)