[json] How to convert a JSON string to a dictionary?

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

This question is related to json swift dictionary nsjsonserialization

The answer is


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

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

for swift 5, I write a demo to verify it.

extension String {

    /// convert JsonString to Dictionary
    func convertJsonStringToDictionary() -> [String: Any]? {
        if let data = data(using: .utf8) {
            return (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]
        }

        return nil
    }
}

let str = "{\"name\":\"zgpeace\"}"
let dict = str.convertJsonStringToDictionary()
print("string > \(str)")  
// string > {"name":"zgpeace"}
print("dicionary > \(String(describing: dict))") 
// dicionary > Optional(["name": zgpeace])

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

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

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

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

}


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

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

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

Examples related to json

Use NSInteger as array index Uncaught SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) HTTP POST with Json on Body - Flutter/Dart Importing json file in TypeScript json.decoder.JSONDecodeError: Extra data: line 2 column 1 (char 190) Angular 5 Service to read local .json file How to import JSON File into a TypeScript file? Use Async/Await with Axios in React.js Uncaught SyntaxError: Unexpected token u in JSON at position 0 how to remove json object key and value.?

Examples related to swift

Make a VStack fill the width of the screen in SwiftUI Xcode 10.2.1 Command PhaseScriptExecution failed with a nonzero exit code Command CompileSwift failed with a nonzero exit code in Xcode 10 Convert Json string to Json object in Swift 4 iOS Swift - Get the Current Local Time and Date Timestamp Xcode 9 Swift Language Version (SWIFT_VERSION) How do I use Safe Area Layout programmatically? How can I use String substring in Swift 4? 'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator Safe Area of Xcode 9 The use of Swift 3 @objc inference in Swift 4 mode is deprecated?

Examples related to dictionary

JS map return object python JSON object must be str, bytes or bytearray, not 'dict Python update a key in dict if it doesn't exist How to update the value of a key in a dictionary in Python? How to map an array of objects in React C# Dictionary get item by index Are dictionaries ordered in Python 3.6+? Split / Explode a column of dictionaries into separate columns with pandas Writing a dictionary to a text file? enumerate() for dictionary in python

Examples related to nsjsonserialization

How to convert a JSON string to a dictionary? Reading in a JSON File Using Swift