0

Im writing my first swift code, trying to play with Json, Im using JSONSerializer found in GitHub to help me convert classes to json, this part works fine, now im trying to convert the Json string to dictionary and get to the data and i unable to do it, Im attaching my playGround code, can someone help me please?

import UIKit
import Foundation

   /// Handles Convertion from instances of objects to JSON strings.      Also     helps with casting strings of JSON to Arrays or Dictionaries.
public class JSONSerializer {

/**
 Errors that indicates failures of JSONSerialization
 - JsonIsNotDictionary: -
 - JsonIsNotArray:          -
 - JsonIsNotValid:          -
 */
public enum JSONSerializerError: ErrorType {
    case JsonIsNotDictionary
    case JsonIsNotArray
    case JsonIsNotValid
}

//http://stackoverflow.com/questions/30480672/how-to-convert-a-json-string-to-a-dictionary
/**
Tries to convert a JSON string to a NSDictionary. NSDictionary can be easier to work with, and supports string bracket referencing. E.g. personDictionary["name"].
- parameter jsonString: JSON string to be converted to a NSDictionary.
- throws: Throws error of type JSONSerializerError. Either JsonIsNotValid or JsonIsNotDictionary. JsonIsNotDictionary will typically be thrown if you try to parse an array of JSON objects.
- returns: A NSDictionary representation of the JSON string.
*/
public static func toDictionary(jsonString: String) throws -> NSDictionary {
    if let dictionary = try jsonToAnyObject(jsonString) as? NSDictionary {
        return dictionary
    } else {
        throw JSONSerializerError.JsonIsNotDictionary
    }
}

/**
 Tries to convert a JSON string to a NSArray. NSArrays can be iterated and each item in the array can be converted to a NSDictionary.
 - parameter jsonString:    The JSON string to be converted to an NSArray
 - throws: Throws error of type JSONSerializerError. Either JsonIsNotValid or JsonIsNotArray. JsonIsNotArray will typically be thrown if you try to parse a single JSON object.
 - returns: NSArray representation of the JSON objects.
 */
public static func toArray(jsonString: String) throws -> NSArray {
    if let array = try jsonToAnyObject(jsonString) as? NSArray {
        return array
    } else {
        throw JSONSerializerError.JsonIsNotArray
    }
}

/**
 Tries to convert a JSON string to AnyObject. AnyObject can then be casted to either NSDictionary or NSArray.
 - parameter jsonString:    JSON string to be converted to AnyObject
 - throws: Throws error of type JSONSerializerError.
 - returns: Returns the JSON string as AnyObject
 */
private static func jsonToAnyObject(jsonString: String) throws -> AnyObject? {
    var any: AnyObject?

    if let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding) {
        do {
            any = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers)
        }
        catch let error as NSError {
            let sError = String(error)
            NSLog(sError)
            throw JSONSerializerError.JsonIsNotValid
        }
    }
    return any
}

/**
 Generates the JSON representation given any custom object of any custom class. Inherited properties will also be represented.
 - parameter object:    The instantiation of any custom class to be represented as JSON.
 - returns: A string JSON representation of the object.
 */
public static func toJson(object: Any) -> String {
    var json = "{"
    let mirror = Mirror(reflecting: object)

    var children = [(label: String?, value: Any)]()
    let mirrorChildrenCollection = AnyRandomAccessCollection(mirror.children)!
    children += mirrorChildrenCollection

    var currentMirror = mirror
    while let superclassChildren = currentMirror.superclassMirror()?.children {
        let randomCollection = AnyRandomAccessCollection(superclassChildren)!
        children += randomCollection
        currentMirror = currentMirror.superclassMirror()!
    }

    let size = children.count
    var index = 0

    for (optionalPropertyName, value) in children {

        /*let type = value.dynamicType
        let typeString = String(type)
        print("SELF: \(type)")*/

        let propertyName = optionalPropertyName!
        let property = Mirror(reflecting: value)

        var handledValue = String()
        if value is Int || value is Double || value is Float || value is Bool {
            handledValue = String(value ?? "null")
        }
        else if let array = value as? [Int?] {
            handledValue += "["
            for (index, value) in array.enumerate() {
                handledValue += value != nil ? String(value!) : "null"
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if let array = value as? [Double?] {
            handledValue += "["
            for (index, value) in array.enumerate() {
                handledValue += value != nil ? String(value!) : "null"
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if let array = value as? [Float?] {
            handledValue += "["
            for (index, value) in array.enumerate() {
                handledValue += value != nil ? String(value!) : "null"
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if let array = value as? [Bool?] {
            handledValue += "["
            for (index, value) in array.enumerate() {
                handledValue += value != nil ? String(value!) : "null"
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if let array = value as? [String?] {
            handledValue += "["
            for (index, value) in array.enumerate() {
                handledValue += value != nil ? "\"\(value!)\"" : "null"
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if let array = value as? [String] {
            handledValue += "["
            for (index, value) in array.enumerate() {
                handledValue += "\"\(value)\""
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if let array = value as? NSArray {
            handledValue += "["
            for (index, value) in array.enumerate() {
                if !(value is Int) && !(value is Double) && !(value is Float) && !(value is Bool) && !(value is String) {
                    handledValue += toJson(value)
                }
                else {
                    handledValue += "\(value)"
                }
                handledValue += (index < array.count-1 ? ", " : "")
            }
            handledValue += "]"
        }
        else if property.displayStyle == Mirror.DisplayStyle.Class {
            handledValue = toJson(value)
        }
        else if property.displayStyle == Mirror.DisplayStyle.Optional {
            let str = String(value)
            if str != "nil" {
                handledValue = String(str).substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(9), end: str.endIndex.advancedBy(-1)))
            } else {
                handledValue = "null"
            }
        }
        else {
            handledValue = String(value) != "nil" ? "\"\(value)\"" : "null"
        }

        json += "\"\(propertyName)\": \(handledValue)" + (index < size-1 ? ", " : "")
        ++index
    }
    json += "}"
    return json
}
}

          /***********************************************************************/
/* This is my code                                                     */
/***********************************************************************/
class jsonContainer{
var json:LoginToSend
init(){
    json = LoginToSend(password:"String",email:"String",
    deviceToken:"String",
    os:"String",
    osType:"String",
    ver:"String",
    height:1,
    width:1,
    IP:"String",
    errorCode:1,
    errorText:"String")

}
}
class LoginToSend{
var pType:String = "Login"
var userList :Array<AnyObject> = []
var deviceList :Array<AnyObject> = []
var errorList :Array<AnyObject> = []


//    var userList:UserList
init(password:String,email:String,
    deviceToken:String,
    os:String,
    osType:String,
    ver:String,
    height:Int,
    width:Int,
    IP:String,
    errorCode:Int,
    errorText:String){

        let userLista = UserList(password: password,email: email)
        userList.append(userLista)
        let deviceLista = DeviceList(deviceToken: deviceToken,
            os: os,
            ver: ver,
            osType: osType,
            height: height,
            width: width,
            IP: IP)
        deviceList.append(deviceLista)
        let errorLista = ErrorList(errorCode: errorCode, errorText: errorText)
        errorList.append(errorLista)

}
}
class UserList{
var Password = ""
var Email = ""
init( password:String,  email:String){
    Password = password
    Email = email
 }

}
class DeviceList{
var deviceToken = ""
var os = ""
var ver = ""
var osType = ""
var height = -1
var width = -1
var IP = ""
init(deviceToken:String, os:String, ver:String, osType:String,height:Int,width:Int,IP:String){
    self.deviceToken = deviceToken
    self.os = os
    self.ver = ver
    self.osType = osType
    self.height = height
    self.width = width
    self.IP = IP
}
}
class ErrorList{
var errorCode = -1
var errorText = ""
init(errorCode:Int,errorText:String)
{
    self.errorCode = errorCode
    self.errorText = errorText
}
}
var loginToSend = LoginToSend(password:"String",email:"String",
deviceToken:"String",
os:"String",
osType:"String",
ver:"String",
height:1,
width:1,
IP:"String",
errorCode:1,
errorText:"String")
//*****************************************************
//* Creating json from my classes                     *
//*****************************************************

var json1 = JSONSerializer.toJson(loginToSend)

// next line Create the structure i need **
json1 = "{\"json\":" + json1 + "}"
print("===== print the consructed json ====")

print(json1)

let data = json1.dataUsingEncoding(NSUTF8StringEncoding,     allowLossyConversion: false)!

let json6 = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
print("==== print the objects created after converting to NSData and  using NSJSONSerialization.JSONObjectWithData====")

print (json6)
//let j = json6[json]
//let c = j[deviceList]
print (json6["json"]!["deviceList"])
let deviceList = json6["json"]!["deviceList"]?!["IP"]
let ip = deviceList?!["IP"]
print("==== Trying to get internal dta and get nil=====")
print (ip)

This is the playGround outPut

===== print the consructed json ==== {"json":{"pType": "Login", "userList": [{"Password": "String", "Email": "String"}], "deviceList": [{"deviceToken": "String", "os": "String", "ver": "String", "osType": "String", "height": 1, "width": 1, "IP": "String"}], "errorList": [{"errorCode": 1, "errorText": "String"}]}} ==== print the objects created after converting to NSData and using NSJSONSerialization.JSONObjectWithData==== ["json": { deviceList = ( { IP = String; deviceToken = String; height = 1; os = String; osType = String; ver = String; width = 1; } ); errorList = ( { errorCode = 1; errorText = String; } ); pType = Login; userList = ( { Email = String; Password = String; } ); }] Optional(( { IP = String; deviceToken = String; height = 1; os = String; osType = String; ver = String; width = 1; } )) ==== Trying to get internal dta and get nil===== nil

Shimon Wiener
  • 1,142
  • 4
  • 18
  • 39
  • What's the problem with your code? – Andrey Gordeev Nov 01 '15 at 06:20
  • I dont know how to get the data , like i try in the lines:let deviceList = json6["json"]!["deviceList"]?!["IP"] let ip = deviceList?!["IP"] print("==== Trying to get internal dta and get nil=====") print (ip) – Shimon Wiener Nov 01 '15 at 06:26
  • What error do you get? What unexpected log? Don't expect we have a playground so we can run all your code, make the question clear on its own. – Wain Nov 01 '15 at 10:04
  • most of the code is a util that convert the classes to jscon my code is marked with a remark, in the last 3 lines i'm trying extract the value "IP" and print it and getting null, but if you don't have playGround i think it will be hard to see it, adding the playground results to original question – Shimon Wiener Nov 01 '15 at 10:23

1 Answers1

1

I only had a look at the last part of your code, the one relevant to your question, and what I saw was that you should really use safe unwrapping.

I made your code work just by getting rid of all the force unwrapping with ! and replacing it with safe optional binding.

Also, deviceList is an array, not a dictionary.

So, after the line let data = json1.dataUsingEncoding....., replace everything with this and it will work:

if let json6 = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject] {
    if let innerJSON = json6["json"] as? [String: AnyObject], let deviceList = innerJSON["deviceList"] as? [[String: AnyObject]] {
        for device in deviceList {
            print(device["IP"])
        }
    }
}

The idea is to cast the objects to their right type with optional binding: json6 is a dictionary, its "json" key has a dictionary for value, and the "deviceList" key of this dictionary contains an array of dictionaries containing IPs.

Note that your JSON data seems to contain errors. The 'IP' field contains the string "String", I'm not sure this is what you expect...

Eric Aya
  • 69,473
  • 35
  • 181
  • 253