【问题标题】:extension of Dictionary where <String, AnyObject>Dictionary <String, AnyObject> 的扩展
【发布时间】:2015-12-13 03:09:33
【问题描述】:

我正在尝试创建一个字典扩展,其中 Dictionary 的类型为

正在寻找许多地方并尝试不同的方法,但似乎都没有奏效。这是其中之一:

extension Dictionary where <String, AnyObject>{
    var jsonString:String {
        return ""
    }
}

另一种由于某种原因实际上不起作用的方法:

extension Dictionary where Key:Hashable, Value:AnyObject {

    var jsonString:String {

        do {
           let stringData = try NSJSONSerialization.dataWithJSONObject(self, options: NSJSONWritingOptions.PrettyPrinted)
            if let string = String(data: stringData, encoding: NSUTF8StringEncoding){
                return string
            }
        }catch _ {

        }
        return ""
    }
}

得到:参数类型“字典”不符合预期的“AnyObject”类型

【问题讨论】:

  • 我相信this question 的答案适用。
  • 该链接有一个非常丑陋的解决方案,当然它应该比创建两个自定义协议更容易

标签: swift dictionary swift2


【解决方案1】:

>=3.1

从3.1开始,我们可以做具体的扩展,即:

extension Dictionary where Key == String {}

我们不能用具体泛型来符合具体类型,即:

extension Dictionary where Key == String

但是,由于 Dictionary 符合序列,而且我们可以使用具体的泛型来符合协议类型,我们可以这样做:

extension Sequence where Iterator.Element == (key: String, value: AnyObject) {
    func doStuff() {...

否则,我们可以将密钥限制为字符串符合的协议,如下所示:

extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
    var jsonString: String {
        return ""
    }
}

根据您更新的答案。 Json 序列化需要一个对象,Swift 字典是结构。您需要转换为NSDictionary 您必须指定Key 以符合NSObject 才能正确转换为NSDictionary

小记:字典已经将约束Key 输入为Hashable,所以你原来的约束没有添加任何东西。

extension Dictionary where Key: NSObject, Value:AnyObject {

    var jsonString:String {

        do {
            let stringData = try NSJSONSerialization.dataWithJSONObject(self as NSDictionary, options: NSJSONWritingOptions.PrettyPrinted)
            if let string = String(data: stringData, encoding: NSUTF8StringEncoding){
                return string
            }
        }catch _ {

        }
        return ""
    }
}

请注意,字典必须符合此类型才能访问扩展。

let dict = ["k" : "v"]

会变成[String : String]类型,所以你必须明确声明:

let dict: [NSObject : AnyObject] = ["k" : "v"]

【讨论】:

  • 这是我从你的代码中得到的:error: type 'Key' constrained to non-protocol type 'String'
  • @MartinR - 感谢您指出,我已将其换成 StringLiteralConvertible。我认为这可能满足意图。
  • 是的,基本上我应该指定协议而不是类型,找到真正帮助我的协议列表developer.apple.com/library/prerelease/ios/documentation/…
  • @AndriusSteponavičius - 见上文
  • 您的字典需要符合类型约束:let dict: [NSObject : AnyObject] = ["k" : "v"]。另一种选择是尝试像if let convertible = self as? [NSObject : AnyObject] 这样的演员,然后用它来制作NSDictionary convertible as NSDictionary
【解决方案2】:

Swift 3 更新
这是我使用ExpressibleByStringLiteral 代表KeyAny 代表Value 的示例。

extension Dictionary where Key: StringLiteralConvertible, Value: Any {
    var jsonString: String? {
        if let dict = (self as AnyObject) as? Dictionary<String, AnyObject> {
            do {
                let data = try JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions(rawValue: UInt.allZeros))
                if let string = String(data: data, encoding: String.Encoding.utf8) {
                    return string
                }
            } catch {
                print(error)
            }
        }
        return nil
    }
}

然后我像这样使用它:

let dict: Dictionary<String, AnyObject> = [...]
let jsonString = dict.jsonString

您可以将 self 转换为 AnyObject 或 NSObject,两者都可以,然后您可以将其解包为 Dictionary 或任何其他特定类型。

【讨论】:

  • 在 swift 3 中:StringLiteralConvertible 现在是:ExpressibleByStringLiteral
【解决方案3】:

所以,Dictionary 是:

public struct Dictionary<Key : Hashable, Value> : CollectionType, DictionaryLiteralConvertible {..}

协议扩展怎么样? :D

extension CollectionType where Self: DictionaryLiteralConvertible, Self.Key == String, Self.Value == AnyObject, Generator.Element == (Self.Key, Self.Value) {
...
}

【讨论】:

    【解决方案4】:

    除了@Logan 提供的答案之外,对于那些希望将自定义属性添加到字符串下标Dictionary 的人来说,这也是可能的(当我遇到这个 SO 问题时希望这样做):

    extension Dictionary where Key: StringLiteralConvertible {
    
        var somePropertyThatIsAColor:UIColor? {
            get {
                return self["someKey"] as? UIColor
            }
            set {
                // Have to cast as optional Value
                self["someKey"] = (newValue as? Value)
        }
    
    }
    

    【讨论】:

      【解决方案5】:

      我无法使任何提供的解决方案在 Swift 3 中运行,但通过利用 Dictionary 和 NSDictionary 之间的桥梁,我可以使这项工作:

      extension NSDictionary {
      
          var jsonString:String {
      
              do {
                  let stringData = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
                  if let string = String(data: stringData, encoding: .utf8) {
                      return string
                  }
              }catch _ {
      
              }
              return ""
          }
      }
      

      【讨论】:

      • 似乎 swift 3 不支持开箱即用的字典扩展。如果您添加此:protocol AnyDict{} extension Dictionary:AnyDict{} 然后执行extension AnyDict{} 您至少可以将 NSDictionary 排除在等式之外。通过as! Dictionary&lt;String,AnyObject&gt; 进行强制转换可能适用于内部扩展方法
      【解决方案6】:

      Swift 3 方法

      extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject
      

      由于 StringLiteralConvertible 现在已被弃用,取而代之的是 ExpressibleByStringLiteral

      【讨论】:

        【解决方案7】:

        任何使用[String:Any] 而不是Dictionary 的人都可以使用以下扩展名

        extension Dictionary where Key == String, Value == Any {
        
            mutating func append(anotherDict:[String:Any]) {
                for (key, value) in anotherDict {
                    self.updateValue(value, forKey: key)
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2016-05-28
          • 1970-01-01
          • 2017-02-27
          • 2016-08-16
          • 2017-04-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-01
          相关资源
          最近更新 更多