Nazadus Nazadus - 4 months ago 15
JSON Question

Swifty Json getting unknown but long way works fine?

I'm attempting to use SwiftyJson to pull some JSON data.
What's unusual is the "println(json)" says "unknowon" while if I pull the JSON data the regular way it works just fine -- the "println(pop)" says medium, as expected.
Below is the code I'm using. I started cutting out parts until I got to "println(json)" and then decided to try and handle it manually to see if it's SwiftyJson or me.
Any suggestions? I'm fairly new to iOS programming so I'm assuming I'm being silly in some form or another.

var ghostlandsJsonUrl: NSURL = NSURL(string: "http://us.battle.net/api/wow/realm/status?realm=Ghostlands")!
var jsonData: NSData!

var request: NSURLRequest = NSURLRequest(URL: ghostlandsJsonUrl)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)

let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
jsonData = data
if(jsonData != nil) {
let json = JSON(jsonData)
println(json)
} else {
println("jsonData: nil value... net down again?")
}

let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let statuses = jsonObject as? NSDictionary{
if let realms = statuses["realms"] as? NSArray{
if let realm = realms[0] as? NSDictionary{
if let pop = realm["population"] as? NSString{
println(pop)
}
}
}
}

});
task.resume()

Answer

Looking at SwiftyJSON source code I can see that JSON is a simple struct. It implements the Printable protocol. Which give support to the print methods.

public var description: String {
        if let string = self.rawString(options:.PrettyPrinted) {
            return string
        } else {
            return "unknown"
        }
    }

Which means that for a reason or another the rawString method returns nil.

public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
        switch self.type {
        case .Array, .Dictionary:
            if let data = self.rawData(options: opt) {
                return NSString(data: data, encoding: encoding)
            } else {
                return nil
            }
        case .String:
            return (self.object as String)
        case .Number:
            return (self.object as NSNumber).stringValue
        case .Bool:
            return (self.object as Bool).description
        case .Null:
            return "null"
        default:
            return nil
        }
    }

As you are fairly new to iOS development, I will tell you that the constructor doesn't expect a NSData object.

Here is the source:

public var object: AnyObject {
    get {
        return _object
    }
    set {
        _object = newValue
        switch newValue {
        case let number as NSNumber:
            if number.isBool {
                _type = .Bool
            } else {
                _type = .Number
            }
        case let string as NSString:
            _type = .String
        case let null as NSNull:
            _type = .Null
        case let array as [AnyObject]:
            _type = .Array
        case let dictionary as [String : AnyObject]:
            _type = .Dictionary
        default:
            _type = .Unknown
            _object = NSNull()
            _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
        }
    }
}

So you should pass it the unserialized NSData as it:

if let jsonData = data {
    //jsonData can't be nil with this kind of if

    let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
    let json = JSON(jsonObject)
    println(json)
    //...