258

I want to make one function in my swift project that converts String to Dictionary json format but I got one error:

Cannot convert expression's type (@lvalue NSData,options:IntegerLitralConvertible ...

This is my code:

func convertStringToDictionary (text:String) -> Dictionary<String,String> {

    var data :NSData = text.dataUsingEncoding(NSUTF8StringEncoding)!
    var json :Dictionary = NSJSONSerialization.JSONObjectWithData(data, options:0, error: nil)
    return json
} 

I make this function in Objective-C :

- (NSDictionary*)convertStringToDictionary:(NSString*)string {
  NSError* error;
  //giving error as it takes dic, array,etc only. not custom object.
  NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
  id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  return json;
}
4
  • What is the value and ket you want in dictionary? Commented May 27, 2015 at 11:07
  • 1
    I update my question... @Amit89 not matter what is value and key!!! Commented May 27, 2015 at 11:10
  • @Amit89 I want when give text to function return json dictionary format Commented May 27, 2015 at 11:11
  • let jsonDictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String: String]; Commented Mar 26, 2018 at 9:40

10 Answers 10

477

Warning: this is a convenience method to convert a JSON string to a dictionary if, for some reason, you have to work from a JSON string. But if you have the JSON data available, you should instead work with the data, without using a string at all.

Swift 3

func convertToDictionary(text: String) -> [String: Any]? {
    if let data = text.data(using: .utf8) {
        do {
            return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        } catch {
            print(error.localizedDescription)
        }
    }
    return nil
}

let str = "{\"name\":\"James\"}"

let dict = convertToDictionary(text: str)

Swift 2

func convertStringToDictionary(text: String) -> [String:AnyObject]? {
    if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
        do {
            return try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject]
        } catch let error as NSError {
            print(error)
        }
    }
    return nil
}

let str = "{\"name\":\"James\"}"

let result = convertStringToDictionary(str)

Original Swift 1 answer:

func convertStringToDictionary(text: String) -> [String:String]? {
    if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
        var error: NSError?
        let json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error) as? [String:String]
        if error != nil {
            println(error)
        }
        return json
    }
    return nil
}

let str = "{\"name\":\"James\"}"

let result = convertStringToDictionary(str) // ["name": "James"]

if let name = result?["name"] { // The `?` is here because our `convertStringToDictionary` function returns an Optional
    println(name) // "James"
}

In your version, you didn't pass the proper parameters to NSJSONSerialization and forgot to cast the result. Also, it's better to check for the possible error. Last note: this works only if your value is a String. If it could be another type, it would be better to declare the dictionary conversion like this:

let json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error) as? [String:AnyObject]

and of course you would also need to change the return type of the function:

func convertStringToDictionary(text: String) -> [String:AnyObject]? { ... }
Sign up to request clarification or add additional context in comments.

Comments

110

I've updated Eric D's answer for Swift 5:

 func convertStringToDictionary(text: String) -> [String: Any]? {
    if let data = text.data(using: .utf8) {
        do {
            let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]
            return json
        } catch {
            print("Something went wrong")
        }
    }
    return nil
}

4 Comments

This example returns nil. let x = "{\"a\":[\"b\":\"B\",\"c\":\"C\"]}" let result = convertStringToDictionary(x)
Why should we use AnyObject for value type? For example, String is a struct but not a class. Can AnyObject work for it?
Using AnyObject means that only class types can be used, which excludes using structs and enums.
Answer is totally wrong. It's :Any, not AnyObject
26

Swift 3:

if let data = text.data(using: String.Encoding.utf8) {
    do {
        let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any]
        print(json)
    } catch {
        print("Something went wrong")
    }
}

Comments

21

Swift 5

extension String {
    func convertToDictionary() -> [String: Any]? {
        if let data = data(using: .utf8) {
            return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        }
        return nil
    }
}

Comments

17

With Swift 3, JSONSerialization has a method called json​Object(with:​options:​). json​Object(with:​options:​) has the following declaration:

class func jsonObject(with data: Data, options opt: JSONSerialization.ReadingOptions = []) throws -> Any

Returns a Foundation object from given JSON data.

When you use json​Object(with:​options:​), you have to deal with error handling (try, try? or try!) and type casting (from Any). Therefore, you can solve your problem with one of the following patterns.


#1. Using a method that throws and returns a non-optional type

import Foundation

func convertToDictionary(from text: String) throws -> [String: String] {
    guard let data = text.data(using: .utf8) else { return [:] }
    let anyResult: Any = try JSONSerialization.jsonObject(with: data, options: [])
    return anyResult as? [String: String] ?? [:]
}

Usage:

let string1 = "{\"City\":\"Paris\"}"
do {
    let dictionary = try convertToDictionary(from: string1)
    print(dictionary) // prints: ["City": "Paris"]
} catch {
    print(error)
}
let string2 = "{\"Quantity\":100}"
do {
    let dictionary = try convertToDictionary(from: string2)
    print(dictionary) // prints [:]
} catch {
    print(error)
}
let string3 = "{\"Object\"}"
do {
    let dictionary = try convertToDictionary(from: string3)
    print(dictionary)
} catch {
    print(error) // prints: Error Domain=NSCocoaErrorDomain Code=3840 "No value for key in object around character 9." UserInfo={NSDebugDescription=No value for key in object around character 9.}
}

#2. Using a method that throws and returns an optional type

import Foundation

func convertToDictionary(from text: String) throws -> [String: String]? {
    guard let data = text.data(using: .utf8) else { return [:] }
    let anyResult: Any = try JSONSerialization.jsonObject(with: data, options: [])
    return anyResult as? [String: String]
}

Usage:

let string1 = "{\"City\":\"Paris\"}"
do {
    let dictionary = try convertToDictionary(from: string1)
    print(String(describing: dictionary)) // prints: Optional(["City": "Paris"])
} catch {
    print(error)
}
let string2 = "{\"Quantity\":100}"
do {
    let dictionary = try convertToDictionary(from: string2)
    print(String(describing: dictionary)) // prints nil
} catch {
    print(error)
}
let string3 = "{\"Object\"}"
do {
    let dictionary = try convertToDictionary(from: string3)
    print(String(describing: dictionary))
} catch {
    print(error) // prints: Error Domain=NSCocoaErrorDomain Code=3840 "No value for key in object around character 9." UserInfo={NSDebugDescription=No value for key in object around character 9.}
}

#3. Using a method that does not throw and returns a non-optional type

import Foundation

func convertToDictionary(from text: String) -> [String: String] {
    guard let data = text.data(using: .utf8) else { return [:] }
    let anyResult: Any? = try? JSONSerialization.jsonObject(with: data, options: [])
    return anyResult as? [String: String] ?? [:]
}

Usage:

let string1 = "{\"City\":\"Paris\"}"
let dictionary1 = convertToDictionary(from: string1)
print(dictionary1) // prints: ["City": "Paris"]
let string2 = "{\"Quantity\":100}"
let dictionary2 = convertToDictionary(from: string2)
print(dictionary2) // prints: [:]
let string3 = "{\"Object\"}"
let dictionary3 = convertToDictionary(from: string3)
print(dictionary3) // prints: [:]

#4. Using a method that does not throw and returns an optional type

import Foundation

func convertToDictionary(from text: String) -> [String: String]? {
    guard let data = text.data(using: .utf8) else { return nil }
    let anyResult = try? JSONSerialization.jsonObject(with: data, options: [])
    return anyResult as? [String: String]
}

Usage:

let string1 = "{\"City\":\"Paris\"}"
let dictionary1 = convertToDictionary(from: string1)
print(String(describing: dictionary1)) // prints: Optional(["City": "Paris"])
let string2 = "{\"Quantity\":100}"
let dictionary2 = convertToDictionary(from: string2)
print(String(describing: dictionary2)) // prints: nil
let string3 = "{\"Object\"}"
let dictionary3 = convertToDictionary(from: string3)
print(String(describing: dictionary3)) // prints: nil

Comments

9

Swift 4

extension String {
    func convertToDictionary() -> [String: Any]? {
        if let data = self.data(using: .utf8) {
            do {
                return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
            } catch {
                print(error.localizedDescription)
            }
        }
        return nil
    }
}

2 Comments

Just another copy paste
if u don't use options, just don't write them: JSONSerialization.jsonObject(with: data)
6

Details

  • Xcode Version 10.3 (10G8), Swift 5

Solution

import Foundation

// MARK: - CastingError

struct CastingError: Error {
    let fromType: Any.Type
    let toType: Any.Type
    init<FromType, ToType>(fromType: FromType.Type, toType: ToType.Type) {
        self.fromType = fromType
        self.toType = toType
    }
}

extension CastingError: LocalizedError {
    var localizedDescription: String { return "Can not cast from \(fromType) to \(toType)" }
}

extension CastingError: CustomStringConvertible { var description: String { return localizedDescription } }

// MARK: - Data cast extensions

extension Data {
    func toDictionary(options: JSONSerialization.ReadingOptions = []) throws -> [String: Any] {
        return try to(type: [String: Any].self, options: options)
    }

    func to<T>(type: T.Type, options: JSONSerialization.ReadingOptions = []) throws -> T {
        guard let result = try JSONSerialization.jsonObject(with: self, options: options) as? T else {
            throw CastingError(fromType: type, toType: T.self)
        }
        return result
    }
}

// MARK: - String cast extensions

extension String {
    func asJSON<T>(to type: T.Type, using encoding: String.Encoding = .utf8) throws -> T {
        guard let data = data(using: encoding) else { throw CastingError(fromType: type, toType: T.self) }
        return try data.to(type: T.self)
    }

    func asJSONToDictionary(using encoding: String.Encoding = .utf8) throws -> [String: Any] {
        return try asJSON(to: [String: Any].self, using: encoding)
    }
}

// MARK: - Dictionary cast extensions

extension Dictionary {
    func toData(options: JSONSerialization.WritingOptions = []) throws -> Data {
        return try JSONSerialization.data(withJSONObject: self, options: options)
    }
}

Usage

let value1 = try? data.toDictionary()
let value2 = try? data.to(type: [String: Any].self)
let value3 = try? data.to(type: [String: String].self)
let value4 = try? string.asJSONToDictionary()
let value5 = try? string.asJSON(to: [String: String].self)

Test sample

Do not forget to paste the solution code here

func testDescriber(text: String, value: Any) {
    print("\n//////////////////////////////////////////")
    print("-- \(text)\n\n  type: \(type(of: value))\n  value: \(value)")
}

let json1: [String: Any] = ["key1" : 1, "key2": true, "key3" : ["a": 1, "b": 2], "key4": [1,2,3]]
var jsonData = try? json1.toData()
testDescriber(text: "Sample test of func toDictionary()", value: json1)
if let data = jsonData {
    print("  Result: \(String(describing: try? data.toDictionary()))")
}

testDescriber(text: "Sample test of func to<T>() -> [String: Any]", value: json1)
if let data = jsonData {
    print("  Result: \(String(describing: try? data.to(type: [String: Any].self)))")
}

testDescriber(text: "Sample test of func to<T>() -> [String] with cast error", value: json1)
if let data = jsonData {
    do {
        print("  Result: \(String(describing: try data.to(type: [String].self)))")
    } catch {
        print("  ERROR: \(error)")
    }
}

let array = [1,4,5,6]
testDescriber(text: "Sample test of func to<T>() -> [Int]", value: array)
if let data = try? JSONSerialization.data(withJSONObject: array) {
    print("  Result: \(String(describing: try? data.to(type: [Int].self)))")
}

let json2 = ["key1": "a", "key2": "b"]
testDescriber(text: "Sample test of func to<T>() -> [String: String]", value: json2)
if let data = try? JSONSerialization.data(withJSONObject: json2) {
    print("  Result: \(String(describing: try? data.to(type: [String: String].self)))")
}

let jsonString = "{\"key1\": \"a\", \"key2\": \"b\"}"
testDescriber(text: "Sample test of func to<T>() -> [String: String]", value: jsonString)
print("  Result: \(String(describing: try? jsonString.asJSON(to: [String: String].self)))")

testDescriber(text: "Sample test of func to<T>() -> [String: String]", value: jsonString)
print("  Result: \(String(describing: try? jsonString.asJSONToDictionary()))")

let wrongJsonString = "{\"key1\": \"a\", \"key2\":}"
testDescriber(text: "Sample test of func to<T>() -> [String: String] with JSONSerialization error", value: jsonString)
do {
    let json = try wrongJsonString.asJSON(to: [String: String].self)
    print("  Result: \(String(describing: json))")
} catch {
    print("  ERROR: \(error)")
}

Test log

//////////////////////////////////////////
-- Sample test of func toDictionary()

  type: Dictionary<String, Any>
  value: ["key4": [1, 2, 3], "key2": true, "key3": ["a": 1, "b": 2], "key1": 1]
  Result: Optional(["key4": <__NSArrayI 0x600002a35380>(
1,
2,
3
)
, "key2": 1, "key3": {
    a = 1;
    b = 2;
}, "key1": 1])

//////////////////////////////////////////
-- Sample test of func to<T>() -> [String: Any]

  type: Dictionary<String, Any>
  value: ["key4": [1, 2, 3], "key2": true, "key3": ["a": 1, "b": 2], "key1": 1]
  Result: Optional(["key4": <__NSArrayI 0x600002a254d0>(
1,
2,
3
)
, "key2": 1, "key1": 1, "key3": {
    a = 1;
    b = 2;
}])

//////////////////////////////////////////
-- Sample test of func to<T>() -> [String] with cast error

  type: Dictionary<String, Any>
  value: ["key4": [1, 2, 3], "key2": true, "key3": ["a": 1, "b": 2], "key1": 1]
  ERROR: Can not cast from Array<String> to Array<String>

//////////////////////////////////////////
-- Sample test of func to<T>() -> [Int]

  type: Array<Int>
  value: [1, 4, 5, 6]
  Result: Optional([1, 4, 5, 6])

//////////////////////////////////////////
-- Sample test of func to<T>() -> [String: String]

  type: Dictionary<String, String>
  value: ["key1": "a", "key2": "b"]
  Result: Optional(["key1": "a", "key2": "b"])

//////////////////////////////////////////
-- Sample test of func to<T>() -> [String: String]

  type: String
  value: {"key1": "a", "key2": "b"}
  Result: Optional(["key1": "a", "key2": "b"])

//////////////////////////////////////////
-- Sample test of func to<T>() -> [String: String]

  type: String
  value: {"key1": "a", "key2": "b"}
  Result: Optional(["key1": a, "key2": b])

//////////////////////////////////////////
-- Sample test of func to<T>() -> [String: String] with JSONSerialization error

  type: String
  value: {"key1": "a", "key2": "b"}
  ERROR: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 21." UserInfo={NSDebugDescription=Invalid value around character 21.}

Comments

4

In 2022 year, I'm using JSONDecoder.

struct GroceryProduct: Codable {
    var name: String
    var points: Int
    var description: String?
}

let json = """
{
    "name": "Durian",
    "points": 600,
    "description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!

let decoder = JSONDecoder()

do {
  let product = try decoder.decode(GroceryProduct.self, from: json)
}
catch { //error handle }

print(product.name) // Prints "Durian"

1 Comment

This is not relevant for the original question, as it assumes the OP knows the format of the incoming data structure
3

I found code which converts the json string to NSDictionary or NSArray. Just add the extension.

SWIFT 3.0

HOW TO USE

let jsonData = (convertedJsonString as! String).parseJSONString

EXTENSION

extension String
{
var parseJSONString: AnyObject?
{
    let data = self.data(using: String.Encoding.utf8, allowLossyConversion: false)
    if let jsonData = data
    {
        // Will return an object or nil if JSON decoding fails
        do
        {
            let message = try JSONSerialization.jsonObject(with: jsonData, options:.mutableContainers)
            if let jsonResult = message as? NSMutableArray {
                return jsonResult //Will return the json array output
            } else if let jsonResult = message as? NSMutableDictionary {
                return jsonResult //Will return the json dictionary output
            } else {
                return nil
            }
        }
        catch let error as NSError
        {
            print("An error occurred: \(error)")
            return nil
        }
    }
    else
    {
        // Lossless conversion of the string was not possible
        return nil
    }
}

}

1 Comment

Don't use NSMutable... collection types in Swift at all. Type cast to NSMutable... will never result a mutable object. And an unspecified type in Swift 3+ is Any, not AnyObject.
-1
let JSONData = jsonString.data(using: .utf8)!

let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)

guard let userDictionary = jsonResult as? Dictionary<String, AnyObject> else {
            throw NSError()}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.