关于mypreviousquestions,我决定将NSArrayController子类化,以实现所需的行为。

class NSPresetArrayController: NSArrayController {
    override func addObject(_ object: Any) {
        if let preset = object as? Preset {
            super.addObject(["name": preset.name, "value": preset.value])
        } else {
            super.addObject(object)
        }
    }
}

这是可行的,但是如果我想要对任何Encodable类都有效的东西,而不仅仅是一个具有两个名为namevalue属性的东西呢?
基本上,问题在于从类中创建字典,其中键是属性名,值是这些属性的值。
我试着这样写:
class NSPresetArrayController: NSArrayController {
    override func addObject(_ object: Any) {
        if let encodableObject = object as? Encodable {
            let data = try! PropertyListEncoder().encode(encodableObject)
            let any = try! PropertyListSerialization.propertyList(from: data, options: [], format: nil)

            super.addObject(any)
        }
    }
}

但是,我得到一个编译错误:
Cannot invoke 'encode' with an argument list of type '(Encodable)'
1. Expected an argument list of type '(Value)'

我该如何修复它以便编译?

最佳答案

问题是protocols don't always conform to themselvesPropertyListEncoderencode(_:)方法需要一个Value : Encodable参数:

func encode<Value : Encodable>(_ value: Value) throws -> Data

但是,Encodable类型本身当前无法满足此约束(但在语言的未来版本中可能会很好地满足)。
正如链接问答(和also here中所探讨的那样,解决这一限制的一种方法是打开Encodable值,以便挖掘出底层的混凝土类型,我们可以将其替换为Value。我们可以通过协议扩展来实现这一点,并使用包装类型来封装它:
extension Encodable {
  fileprivate func openedEncode(to container: inout SingleValueEncodingContainer) throws {
    try container.encode(self)
  }
}

struct AnyEncodable : Encodable {
  var value: Encodable
  init(_ value: Encodable) {
    self.value = value
  }
  func encode(to encoder: Encoder) throws {
    var container = encoder.singleValueContainer()
    try value.openedEncode(to: &container)
  }
}

应用于您的示例:
class NSPresetArrayController : NSArrayController {
  override func addObject(_ object: Any) {
    guard let object = object as? Encodable else {
      // Not encodable, maybe do some error handling.
      return
    }
    do {
      let encoded = try PropertyListEncoder().encode(AnyEncodable(object))
      let cocoaPropertyList = try PropertyListSerialization.propertyList(from: encoded, format: nil)
      super.addObject(cocoaPropertyList)
    } catch {
      // Couldn't encode. Do some error handling.
    }
  }
}

关于swift - 将类型为Any的Swift Encodable类转换为字典,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54392379/

10-16 11:49