extension of Dictionary where <String, AnyObject>

SwiftDictionarySwift2

Swift Problem Overview


I am trying to create a dictionary extension where Dictionary is of the type <String, AnyObject>.

Was looking in many places and trying different approaches, but none of them seemed to work. This was one of them:

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

Another method that didn't actually work for some reason:

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: Argument type 'Dictionary' does not conform to expected type of 'AnyObject'

Swift Solutions


Solution 1 - Swift

>=3.1

From 3.1, we can do concrete extensions, ie:

extension Dictionary where Key == String {}

<3.1

We can not conform concrete types w/ concrete generics, ie:

extension Dictionary where Key == String

However, because Dictionary conforms to sequence and we can conform protocol types w/ concrete generics, we could do:

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

Otherwise, we can constrain our key to a protocol that string conforms to like this:

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

As per your updated answer. Json serialization needs an object, Swift Dictionaries are structs. You need to convert to an NSDictionary You must specify Key to conform to NSObject to properly convert to an NSDictionary.

> Small note: Dictionaries already type constrain Key to be Hashable, so your original constraint wasn't adding anything.

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

Note, that the dictionaries must conform to this type to access the extension.

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

Will become type [String : String], so you must be explicit in declaring:

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

Solution 2 - Swift

Update for Swift 3
Here is my example using ExpressibleByStringLiteral for Key and Any for 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
    }
}

and then I use it like this:

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

You can convert self to AnyObject or NSObject, both works, then you do unwrap as Dictionary or any other specific type.

Solution 3 - Swift

Swift 3 Approach

extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject

As StringLiteralConvertible is now deprecated and replaced by ExpressibleByStringLiteral

Solution 4 - Swift

Adding to the answer provided by @Logan, for those looking to add custom properties to the string-subscripted Dictionary, that is possible as well (was looking to do this when I came across this SO question):

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

}

Solution 5 - Swift

So, Dictionary is:

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

How about a protocol extension? :D

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

Solution 6 - Swift

Anyone using [String:Any] instead of Dictionary can use below extension

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

Solution 7 - Swift

I was not able to make any of the offered solutions work in Swift 3, but by taking advantage of bridging between Dictionary and NSDictionary I could make this work:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndrius SteponavičiusView Question on Stackoverflow
Solution 1 - SwiftLoganView Answer on Stackoverflow
Solution 2 - SwiftJonauzView Answer on Stackoverflow
Solution 3 - SwiftAidan MaloneView Answer on Stackoverflow
Solution 4 - SwiftJason HendersonView Answer on Stackoverflow
Solution 5 - SwiftAndrei PopaView Answer on Stackoverflow
Solution 6 - SwiftDhaval H. NenaView Answer on Stackoverflow
Solution 7 - SwiftDrew CView Answer on Stackoverflow