Swift extension for Dictionary. Error 'Cannot invoke 'dataWithJSONObject' - ios

I am newbie in swift. I have stuck in creating extension for Dictionary.
My extension is:
extension Dictionary {
var JSONString: String {
var error: NSError?
var jsonData: NSData? = NSJSONSerialization.dataWithJSONObject(self, options: NSJSONWritingOptions.PrettyPrinted, error: &error)
if error == nil {
return NSString(data: jsonData!, encoding: NSUTF8StringEncoding) as! String
}
return ""
}
}
I get an error message
Cannot invoke ‘dataWithJSONObject’ with an argument of type ‘(Dictionary , options:NSJSONWritingOptions, error: inout NSError?)’
Can anybody help me to resolve this problem?

I have just found a solution and understood my mistake.
Correct code is
extension Dictionary {
var JSONString: String {
var error: NSError?
var dictionary: [String: AnyObject] = [:]
for (key, value) in self {
dictionary["\(key)"] = "\(value)"
}
var jsonData: NSData = NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions.PrettyPrinted, error: &error)!
if error == nil {
return NSString(data: jsonData, encoding: NSUTF8StringEncoding)! as String
}
return ""
}
}
Thank you all

Related

Cannot downcast from 'Any' to a more optional type '[String : AnyObject]?'

I am trying to fetch the json from url. While Serialization json it is giving error?
static func fetchFeatureApp(){
let urlString="http://ebmacs.net/ubereats/Api/all_product?id=1"
let url = URL(string: urlString)!
URLSession.shared.dataTask(with: URLRequest(url: url)){ (data, responce, error) in
if error != nil
{
print(error)
return
}
do{
let json=try (JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) //as! [String:AnyObject]?//as! [AnyObject]?//as! String? //as! [String:AnyObject]//as! [String: Any]
//////////Error here
//let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: Any] //program is crashing
var appCategories=[AppCategory]()
for dict in json["products"] as! [[String :AnyObject]]{///////Error Here
let appCategory = AppCategory()
appCategory.setValuesForKeys(dict)
appCategories.append(appCategory)
}
print(appCategories)
}catch let err{
print(error)
}
}.resume()
}
The class for Json is
class App:NSObject {
var product_id:NSNumber?
var product_name:String?
var product_description:String?
var image_url:String?
var product_price:NSNumber?
var name:String?
}
image description here
At following lines I am getting error:
Error 1:
`let json=try (JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) //as! [String:AnyObject]?//as! [AnyObject]?//as! String? //as! [String:AnyObject]//as! [String: Any]`
Cannot downcast from 'Any' to a more optional type '[String :
AnyObject]?'
Error 2:
for dict in json["products"] as! [[String :AnyObject]]{ /////////////error
Type 'Any' has no subscript members
How to remove these error ?
The recommended way to parse JSON is to unwrap the optional safely with optional bindings.
Please read the JSON. It's very easy. {} represents a dictionary ([String:Any] in Swift), [] an array ([[String:Any]]) and .mutableContainers is nonsense in Swift anyway.
The root object is a dictionary, the value for key products is an array
struct AppCategory {
let id, name, description, url, price : String
}
do {
if let jsonResult = try JSONSerialization.jsonObject(with:data!) as? [String:Any] {
if let products = jsonResult["products"] as? [[String:String]] {
var appCategories = [AppCategory]()
for product in products {
let category = AppCategory(id: product["product_id"] ?? "",
name: product["product_name"] ?? "",
description: product["product_description"] ?? "",
url: product["image_url"] ?? "",
price: product["product_price"] ?? "")
appCategories.append(category)
}
print(appCategories)
}
}
} catch {
print(error)
}
Try this:
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any]
Edit: This would only work if the top level object in your json is actually a dictionary and not an array. Would be helpful if you could post a redacted version of your json response.
This code is working for me with your url.

Return JSON on output Swift [duplicate]

I have create the next Dictionary:
var postJSON = [ids[0]:answersArray[0], ids[1]:answersArray[1], ids[2]:answersArray[2]] as Dictionary
and I get:
[2: B, 1: A, 3: C]
So, how can I convert it to JSON?
Swift 3.0
With Swift 3, the name of NSJSONSerialization and its methods have changed, according to the Swift API Design Guidelines.
let dic = ["2": "B", "1": "A", "3": "C"]
do {
let jsonData = try JSONSerialization.data(withJSONObject: dic, options: .prettyPrinted)
// here "jsonData" is the dictionary encoded in JSON data
let decoded = try JSONSerialization.jsonObject(with: jsonData, options: [])
// here "decoded" is of type `Any`, decoded from JSON data
// you can now cast it with the right type
if let dictFromJSON = decoded as? [String:String] {
// use dictFromJSON
}
} catch {
print(error.localizedDescription)
}
Swift 2.x
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dic, options: NSJSONWritingOptions.PrettyPrinted)
// here "jsonData" is the dictionary encoded in JSON data
let decoded = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
// here "decoded" is of type `AnyObject`, decoded from JSON data
// you can now cast it with the right type
if let dictFromJSON = decoded as? [String:String] {
// use dictFromJSON
}
} catch let error as NSError {
print(error)
}
Swift 1
var error: NSError?
if let jsonData = NSJSONSerialization.dataWithJSONObject(dic, options: NSJSONWritingOptions.PrettyPrinted, error: &error) {
if error != nil {
println(error)
} else {
// here "jsonData" is the dictionary encoded in JSON data
}
}
if let decoded = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as? [String:String] {
if error != nil {
println(error)
} else {
// here "decoded" is the dictionary decoded from JSON data
}
}
You are making a wrong assumption. Just because the debugger/Playground shows your dictionary in square brackets (which is how Cocoa displays dictionaries) that does not mean that is the way the JSON output is formatted.
Here is example code that will convert a dictionary of strings to JSON:
Swift 3 version:
import Foundation
let dictionary = ["aKey": "aValue", "anotherKey": "anotherValue"]
if let theJSONData = try? JSONSerialization.data(
withJSONObject: dictionary,
options: []) {
let theJSONText = String(data: theJSONData,
encoding: .ascii)
print("JSON string = \(theJSONText!)")
}
To display the above in "pretty printed" format you'd change the options line to:
options: [.prettyPrinted]
Or in Swift 2 syntax:
import Foundation
let dictionary = ["aKey": "aValue", "anotherKey": "anotherValue"]
let theJSONData = NSJSONSerialization.dataWithJSONObject(
dictionary ,
options: NSJSONWritingOptions(0),
error: nil)
let theJSONText = NSString(data: theJSONData!,
encoding: NSASCIIStringEncoding)
println("JSON string = \(theJSONText!)")
The output of that is
"JSON string = {"anotherKey":"anotherValue","aKey":"aValue"}"
Or in pretty format:
{
"anotherKey" : "anotherValue",
"aKey" : "aValue"
}
The dictionary is enclosed in curly braces in the JSON output, just as you'd expect.
EDIT:
In Swift 3/4 syntax, the code above looks like this:
let dictionary = ["aKey": "aValue", "anotherKey": "anotherValue"]
if let theJSONData = try? JSONSerialization.data(
withJSONObject: dictionary,
options: .prettyPrinted
),
let theJSONText = String(data: theJSONData,
encoding: String.Encoding.ascii) {
print("JSON string = \n\(theJSONText)")
}
}
Swift 5:
let dic = ["2": "B", "1": "A", "3": "C"]
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(dic) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
}
Note that keys and values must implement Codable. Strings, Ints, and Doubles (and more) are already Codable. See Encoding and Decoding Custom Types.
Also note that Any does not conform to Codable. It is likely still a good approach to adapt your data to become Codable so that you are making use of Swift typing (especially in the case that you are also going to decode any encoded json), and so that you can be more declarative about the outcome of your encoding.
My answer for your question is below
let dict = ["0": "ArrayObjectOne", "1": "ArrayObjecttwo", "2": "ArrayObjectThree"]
var error : NSError?
let jsonData = try! NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions.PrettyPrinted)
let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String
print(jsonString)
Answer is
{
"0" : "ArrayObjectOne",
"1" : "ArrayObjecttwo",
"2" : "ArrayObjectThree"
}
Swift 4 Dictionary extension.
extension Dictionary {
var jsonStringRepresentation: String? {
guard let theJSONData = try? JSONSerialization.data(withJSONObject: self,
options: [.prettyPrinted]) else {
return nil
}
return String(data: theJSONData, encoding: .ascii)
}
}
Sometimes it's necessary to print out server's response for debugging purposes. Here's a function I use:
extension Dictionary {
var json: String {
let invalidJson = "Not a valid JSON"
do {
let jsonData = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return String(bytes: jsonData, encoding: String.Encoding.utf8) ?? invalidJson
} catch {
return invalidJson
}
}
func printJson() {
print(json)
}
}
Example of use:
(lldb) po dictionary.printJson()
{
"InviteId" : 2,
"EventId" : 13591,
"Messages" : [
{
"SenderUserId" : 9514,
"MessageText" : "test",
"RecipientUserId" : 9470
},
{
"SenderUserId" : 9514,
"MessageText" : "test",
"RecipientUserId" : 9470
}
],
"TargetUserId" : 9470,
"InvitedUsers" : [
9470
],
"InvitingUserId" : 9514,
"WillGo" : true,
"DateCreated" : "2016-08-24 14:01:08 +00:00"
}
Swift 5:
extension Dictionary {
/// Convert Dictionary to JSON string
/// - Throws: exception if dictionary cannot be converted to JSON data or when data cannot be converted to UTF8 string
/// - Returns: JSON string
func toJson() throws -> String {
let data = try JSONSerialization.data(withJSONObject: self)
if let string = String(data: data, encoding: .utf8) {
return string
}
throw NSError(domain: "Dictionary", code: 1, userInfo: ["message": "Data cannot be converted to .utf8 string"])
}
}
Swift 3:
let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: [])
let jsonString = String(data: jsonData!, encoding: .utf8)!
print(jsonString)
In Swift 5.4
extension Dictionary {
var jsonData: Data? {
return try? JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted])
}
func toJSONString() -> String? {
if let jsonData = jsonData {
let jsonString = String(data: jsonData, encoding: .utf8)
return jsonString
}
return nil
}
}
The idea of having it as a variable is because then you can reuse it like that:
extension Dictionary {
func decode<T:Codable>() throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData ?? Data())
}
}
Answer for your question is below:
Swift 2.1
do {
if let postData : NSData = try NSJSONSerialization.dataWithJSONObject(dictDataToBeConverted, options: NSJSONWritingOptions.PrettyPrinted){
let json = NSString(data: postData, encoding: NSUTF8StringEncoding)! as String
print(json)}
}
catch {
print(error)
}
Here's an easy extension to do this:
https://gist.github.com/stevenojo/0cb8afcba721838b8dcb115b846727c3
extension Dictionary {
func jsonString() -> NSString? {
let jsonData = try? JSONSerialization.data(withJSONObject: self, options: [])
guard jsonData != nil else {return nil}
let jsonString = String(data: jsonData!, encoding: .utf8)
guard jsonString != nil else {return nil}
return jsonString! as NSString
}
}
using lldb
(lldb) p JSONSerialization.data(withJSONObject: notification.request.content.userInfo, options: [])
(Data) $R16 = 375 bytes
(lldb) p String(data: $R16!, encoding: .utf8)!
(String) $R18 = "{\"aps\": \"some_text\"}"
//or
p String(data: JSONSerialization.data(withJSONObject: notification.request.content.userInfo, options: [])!, encoding: .utf8)!
(String) $R4 = "{\"aps\": \"some_text\"}"
do{
let dataDict = [ "level" :
[
["column" : 0,"down" : 0,"left" : 0,"right" : 0,"row" : 0,"up" : 0],
["column" : 1,"down" : 0,"left" : 0,"right" : 0,"row" : 0,"up" : 0],
["column" : 2,"down" : 0,"left" : 0,"right" : 0,"row" : 0,"up" : 0],
["column" : 0,"down" : 0,"left" : 0,"right" : 0,"row" : 1,"up" : 0],
["column" : 1,"down" : 0,"left" : 0,"right" : 0,"row" : 1,"up" : 0],
["column" : 2,"down" : 0,"left" : 0,"right" : 0,"row" : 1,"up" : 0]
]
]
var jsonData = try JSONSerialization.data(withJSONObject: dataDict, options: JSONSerialization.WritingOptions.prettyPrinted)
let jsonStringData = NSString(data: jsonData as Data, encoding: NSUTF8StringEncoding)! as String
print(jsonStringData)
}catch{
print(error.localizedDescription)
}
This works for me:
import SwiftyJSON
extension JSON {
mutating func appendIfKeyValuePair(key: String, value: Any){
if var dict = self.dictionaryObject {
dict[key] = value
self = JSON(dict)
}
}
}
Usage:
var data: JSON = []
data.appendIfKeyValuePair(key: "myKey", value: "myValue")
2022, swift 5
usage of extensions:
Encode:
if let json = statisticsDict.asJSONStr() {
//your action with json
}
Decode from Dictionary:
json.decodeFromJson(type: [String:AppStat].self)
.onSuccess{
$0// your dictionary of type: [String:AppStat]
}
extensions:
extension Dictionary where Key: Encodable, Value: Encodable {
func asJSONStr() -> String? {
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(self) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
return jsonString
}
}
return nil
}
}
public extension String {
func decodeFromJson<T>(type: T.Type) -> Result<T, Error> where T: Decodable {
self.asData()
.flatMap { JSONDecoder().try(type, from: $0) }
}
func asData() -> Result<Data, Error> {
if let data = self.data(using: .utf8) {
return .success(data)
} else {
return .failure(WTF("can't convert string to data: \(self)"))
}
}
}
extension JSONDecoder {
func `try`<T: Decodable>(_ t: T.Type, from data: Data) -> Result<T,Error> {
do {
return .success(try self.decode(t, from: data))
} catch {
return .failure(error)
}
}
}
private func convertDictToJson(dict : NSDictionary) -> NSDictionary?
{
var jsonDict : NSDictionary!
do {
let jsonData = try JSONSerialization.data(withJSONObject:dict, options:[])
let jsonDataString = String(data: jsonData, encoding: String.Encoding.utf8)!
print("Post Request Params : \(jsonDataString)")
jsonDict = [ParameterKey : jsonDataString]
return jsonDict
} catch {
print("JSON serialization failed: \(error)")
jsonDict = nil
}
return jsonDict
}

swift Dictionary with [UInt8] as value convert to json string

I create a swift class as shown below:
class Message {
var type:String
var content:[UInt8] = [UInt8]()
init(type:String, content:[UInt8]) {
self.type = type
self.content = content
}
func jsonAsString()->String {
var dict = [String: AnyObject]()
let mirror = Mirror(reflecting: self)
for (_, attr) in mirror.children.enumerate() {
if let property_name = attr.label as String! {
print("property_name: \(property_name) and value:\(attr.value)")
dict[property_name] = attr.value as? AnyObject
}
}
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions.PrettyPrinted)
return (String(data: jsonData, encoding: NSUTF8StringEncoding)?.stringByReplacingOccurrencesOfString(" ", withString: ""))!
} catch {
NSLog("ERROR when parse JSON")
}
return ""
}
}
I want to call the function 'jsonAsString' to get a json string, but the property 'content' which is an uint8 array not convert correctly.
As I found a lot, some one suggest to replace
var dict = String: AnyObject with
var dict = String: Any
But this type of dictionary is not supported by the method
NSJSONSerialization.dataWithJSONObject(obj: AnyObject, options opt: NSJSONWritingOptions) throws -> NSData

Swift using String to create JSON object

I am trying to use a string I am getting from a database as JSON using swift. I have tried to convert the string to a data object and then use JSONSerialization, but the results always come back nil.
Here is a sample of my code:
var string = "{Param1: \"Value\", Param2: \"value2\", Param3: \"value3\"}"
let data = (reducedOptionsString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
if let d = data{
var err : NSErrorPointer = nil
let parsedObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(d, options: NSJSONReadingOptions.MutableLeaves, error: err)
if let dict = parsedObject as? Dictionary<String, AnyObject>{
...
}
}
For some reason parsedObject always comes back as nil
Does anyone know what I might be missing to convert my string data to a JSON object that I can use?
Your json is not valid, keys must me enclosed in quotes too.
"{ \"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
Also, as #zaph pointed out, it's variable string the one you want to convert to data.
var string = "{\"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
if let data = string.dataUsingEncoding(NSUTF8StringEncoding){
var err : NSErrorPointer = nil
let parsedObject = NSJSONSerialization.JSONObjectWithData(
data!,
options: NSJSONReadingOptions.MutableLeaves,
error: err) as? Dictionary<String, AnyObject>
if (parsedObject != nil) {
...
}
else {
if (err != nil) {
println("Error: \(err)")
}
else {
println("Error: unexpected error parsing json string")
}
}
}
Alternatively, you could use SwiftyJSON, a very popular library to handle json on swift that could make your life a little easier.
var string = "{\"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
if let data = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
{
var err : NSErrorPointer = nil
let parsedObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: err)
if (err != nil)
{
println("error handling...")
}
if let dict = parsedObject as? Dictionary<String, AnyObject>
{
println("XD")
}
}
You just replace following 2 lines in your OWN code, rest will be work fine.
:)
var string = "{\"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
let data = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
Swift 5 Example:
let properties: [(String, Any?)] = [("firstName", firstName),
("lastName", lastName),
("city", city),
("state", state),
("zipCode", zipCode),
("country", country)]
let body = properties.compactMap({ property -> (String, Any)? in
if let value = property.1 {
return (property.0, value)
} else {
return nil
}
})
let jsonDict = Dictionary(uniqueKeysWithValues: body)
let jsonData = try? JSONSerialization.data(withJSONObject: jsonDict, options: [])

iOS: Get String from NSDictionary in Swift

I have an NSDictionary object.
How do i get json String from this object?
var myNSDictObject ...
...
println(myNSDictObject.description)
This prints a pretty formatted string, with semicolons, newlines inserted etc.. it is not even proper json. So this does not work.
func generateJSONString(dictionary : NSDictionary) -> NSString? {
var error : NSError?
if let data = NSJSONSerialization.dataWithJSONObject(dictionary, options: nil, error: &error) {
return NSString(data: data, encoding: NSUTF8StringEncoding)
} else {
println("\(error?.localizedDescription)")
return nil
}
}

Resources