Подтвердить что ты не робот

Расширение словаря, где <String, AnyObject>

Я пытаюсь создать расширение словаря, где Словарь имеет тип < String, AnyObject > .

Смотрел во многих местах и ​​пытался использовать разные подходы, но никто из них, похоже, не работал. Это был один из них:

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 ""
    }
}

Got: Тип аргумента "Словарь" не соответствует ожидаемому типу "AnyObject"

4b9b3361

Ответ 1

>= 3.1

Из 3.1 мы можем сделать конкретные расширения, т.е.

extension Dictionary where Key == String {}

< 3,1

Мы не можем согласовывать конкретные типы с конкретными дженериками, т.е.

extension Dictionary where Key == String

Однако, поскольку словарь соответствует последовательности, и мы можем согласовывать типы протоколов с конкретными генериками, мы могли бы сделать:

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

В противном случае мы можем ограничить наш ключ протоколом, который соответствует этой строке:

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

Согласно вашему обновленному ответу. Сериализация Json требует объекта, Swift Dictionaries - это структуры. Вам нужно преобразовать в NSDictionary. Вы должны указать Key для соответствия NSObject, чтобы правильно преобразовать в NSDictionary.

Небольшое примечание: словари уже имеют тип constrain 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"]

Ответ 2

Подход Swift 3

extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject

Так как StringLiteralConvertible теперь устарел и заменен ExpressibleByStringLiteral

Ответ 3

Добавляя к ответу, предоставленному @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)
    }

}

Ответ 4

Обновление для Swift 3
Вот мой пример, используя ExpressibleByStringLiteral для Key и Any для 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

Вы можете преобразовать себя в AnyObject или NSObject, оба работают, затем вы разворачиваете словарь или какой-либо другой конкретный тип.

Ответ 5

Итак, 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) {
...
}

Ответ 6

Я не смог сделать ни одно из предлагаемых решений в Swift 3, но, воспользовавшись мостом между Словарем и 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 ""
    }
}

Ответ 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)
        }
    }
}