Is there a protocol for all property-list objects?

怎甘沉沦 提交于 2020-05-28 08:06:12

问题


By convention, each Cocoa and Core Foundation object listed in Table 2-1 is called a property-list object.

So, does this protocol (known as PropertyListObject in the code below) exist, or do we need to make our own? If we do need to make our own, has someone made a definitive one?

public protocol UserDefaults_Value_WrappedValue {
  associatedtype PropertyListObject: HM.PropertyListObject
  init?(propertyListObject: Any)
  var convertertedToPropertyListObject: PropertyListObject { get }
}

public protocol PropertyListObject: UserDefaults_Value_WrappedValue
where PropertyListObject == Self { }

public extension PropertyListObject {
  init?(propertyListObject: Any) {
    guard let object = propertyListObject as? Self
    else { return nil }

    self = object
  }

  var convertertedToPropertyListObject: Self { self }
}

extension Bool: PropertyListObject { }
extension Data: PropertyListObject { }
extension Date: PropertyListObject { }
extension String: PropertyListObject { }
extension URL: PropertyListObject { }

extension Int: PropertyListObject { }
extension Int8: PropertyListObject { }
extension Int16: PropertyListObject { }
extension Int32: PropertyListObject { }
extension Int64: PropertyListObject { }
extension UInt: PropertyListObject { }
extension UInt8: PropertyListObject { }
extension UInt16: PropertyListObject { }
extension UInt32: PropertyListObject { }
extension UInt64: PropertyListObject { }
extension Float: PropertyListObject { }
extension Double: PropertyListObject { }

extension Array: PropertyListObject & UserDefaults_Value_WrappedValue
where Element: HM.PropertyListObject {
  public typealias PropertyListObject = Self
}

extension Dictionary: UserDefaults_Value_WrappedValue
where Key: LosslessStringConvertible, Value: HM.PropertyListObject {
  public typealias PropertyListObject = PropertyListDictionary<Value>

  public init?(propertyListObject: Any) {
    guard let dictionary = propertyListObject as? PropertyListObject
    else { return nil }

    self.init(dictionary)
  }

  public var convertertedToPropertyListObject: PropertyListObject {
    .init(self)
  }
}

extension Dictionary: PropertyListObject
where Key == String, Value: HM.PropertyListObject { }

public typealias PropertyListDictionary<Value: PropertyListObject> = [String: Value]

import CoreGraphics
extension CGPoint: PropertyListObject { }
extension CGVector: PropertyListObject { }
extension CGSize: PropertyListObject { }
extension CGRect: PropertyListObject { }
extension CGAffineTransform: PropertyListObject { }

Use case:

The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.

final class UserDefaultsTestCase: XCTestCase {
  func test_subscript() {
    let key = "🔑"

    UserDefaults[key] = true
    XCTAssert(UserDefaults[key] == true)

    UserDefaults[key] = 9
    XCTAssertEqual(UserDefaults[key], 9)
  }

  func test_Dictionary() {
    let key = "🔑"

    UserDefaults[key] = Day.ta
    XCTAssertEqual(UserDefaults["🔑"], Day.ta)

    UserDefaults[key] = [1: "🌞", 2: "🌛"]
    XCTAssertEqual(UserDefaults["🔑"], Day.ta)

    UserDefaults.standard[key] = ["1": "🌞", "2": "🌛"]
    XCTAssertEqual(UserDefaults["🔑"], Day.ta)
  }

  func test_propertyWrapper() {
    struct Type {
      @UserDefaults.Value(key: "🗝") var dayta = Day.ta
    }

    var instance = Type()
    XCTAssertEqual(instance.dayta, Day.ta)
    instance.dayta = nil
    XCTAssertNil(instance.dayta)
  }
}

private enum Day: Int, LosslessStringConvertible {
  case sunday = 1, monday

  static let ta = [Day.sunday: "🌞", .monday: "🌛"]
}
public extension UserDefaults {
  @propertyWrapper struct Value<WrappedValue: UserDefaults_Value_WrappedValue> {
    public init(
      wrappedValue: WrappedValue?,
      key: String,
      defaults: UserDefaults = .standard
    ) {
      self.key = key
      self.defaults = defaults
      self.wrappedValue = wrappedValue
    }

    public var wrappedValue: WrappedValue? {
      get { defaults[key] }
      set { defaults[key] = newValue }
    }

    public let key: String
    private let defaults: UserDefaults
  }

  static subscript<Object: UserDefaults_Value_WrappedValue>(key: String) -> Object? {
    get { standard[key] }
    set { standard[key] = newValue }
  }

  subscript<Object: UserDefaults_Value_WrappedValue>(key: String) -> Object? {
    get { object(forKey: key).flatMap(Object.init)  }
    set { set(newValue?.convertertedToPropertyListObject, forKey: key) }
  }
}

More reading: https://github.com/apple/swift-evolution/blob/master/proposals/0139-bridge-nsnumber-and-nsvalue.md

来源:https://stackoverflow.com/questions/61333470/is-there-a-protocol-for-all-property-list-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!