Расширение словаря, где <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"
Ответы
Ответ 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)
}
}
}