How to parse JSON in Swift 2? - json

I have a PHP web api that returns json in the following format:
{"users":[
{"user": {id:"1","name":"ahmad"}},
...
]}
In my Swift 2 code, I am able to retrieve the data above store it in an NSArray named users
Now, I need to iterate throw each user to convert it into an object:
for user in users {
print("found: \(user)")
}
That ouputs something like:
found: {
user = {
id = 1;
name = ahmad;
};
}
but when I try to access any element of that object I get an error:
let id = user["user"]["id"] //does not work: Xcode wont compile
let id2 = user["user"]!["id"]! //does not work: Xcode wont compile
let id3 = user!["user"]!["id"]! //does not work: Xcode wont compile
Then I tried :
if let u=user["user"] { //does not work: Xcode wont compile
// do somthing
}
I put a break point at print("\(user)") to see what is going on, and here is what I found:
When I print the description of each individual user I get:
How can I access the elements of this JSON data in Swift 2?

A NSArray only holds AnyObject so you have to cast it (to Array<Dictionary<String, Dictionary<String, String>>>. Below you see the shorthand):
// this is a forced cast and you probably get runtime errors if users cannot be casted
for user in users as! [[String : [String : String]]] {
print("found: \(user)")
}

Related

Fetch first element in JSON with Swift

I have a JSON string, an example is shown in the screenshot below. How can I print to the console the first element from a given array?
I've tried different options for converting a date to a string, but the string won't let me get the first element in its entirety
I recommend using a package like SwiftyJSON to work with JSON in Swift. You can add it via Swift Package Manager or CocoaPods, whichever you prefer.
Supposing to have this JSON string:
let json = "[{\"id\" : 0, \"text\" : \"hello\"},{\"id\" : 1, \"text\" : \"hi\"}]"
You can parse it as shown, and then retrieve and print to console the first item:
if let data = json.data(using: .utf8) {
if let json = try? JSON(data: data) {
print(json[0])
}
}
This will print on the console as:
{
"text" : "hello",
"id" : 0
}
Remember to import SwiftyJSON at the top of the swift file

AlamoFire 4.0 + SwiftyJSON Unwrapping deeply nested JSON

I'm having issues parsing the JSON I'm getting back from the Wiki API.
Podfile:
platform :ios, ’10.0’
inhibit_all_warnings!
use_frameworks!
target 'GemFinder' do
pod 'Alamofire', '~> 4.0’
pod 'SwiftyJSON', :git => 'https://github.com/appsailor/SwiftyJSON.git', :branch => 'swift3'
end
Swift Code:
import UIKit
import Alamofire
import SwiftyJSON
class WikiAPI: NSObject {
func MineralRequest(minID: (String)) {
Alamofire.request("https://en.wikipedia.org/w/api.php?action=query&titles=\(minID)&exintro=1&prop=pageimages%7Cextracts&format=json&pithumbsize=300", parameters: ["query": "pages"]).responseJSON { response in
if let values = response.result.value as? [String: AnyObject] {
let json = JSON(values)
// Returns null
print("otherJSON: \(json["query"]["pages"][0]["extract"])")
let JSONvalues = values as NSDictionary
print("JSONvalues: \(JSONvalues)")
// This is also working to retrieve everything from below "query"
let parse = JSONvalues.object(forKey: "query")
print("Parse: \(parse)")
let queryValues = values["query"]
// Returns nested "pages" object, but I need to go deeper.
print("queryvalues: \(queryValues?["pages"])")
}
}
}
}
I'm able to get a response, of course, and trying to go deeper, but I keep getting null values when trying to unwrap.
What am I missing? Here's an image of the tree. I'm trying to pull title, images and the extract out.
JSON response preview
Following this format, as seen here, still yields null values. Parameters didn't seem to benefit either: How do I access a nested JSON value using Alamofire and SwiftyJSON?
"pages" value is a dictionary so using [0] on it won't work, you need to use the key instead:
print("otherJSON: \(json["query"]["pages"]["1895477"]["extract"])")
Or if there are many items in pages and you want them all you can iterate through it like:
let pages = json["query"]["pages"]
for (_,page) in pages {
print(page["extract"])
}

How to create JSON format from Realm "Results" using Object Mapper

I try to create JSON format from Realm Results using Object Mapper. So, I created two generic methods to do that. Fisrt method create array form Results and looks like that:
var allRealmData: Results<Project>? // in this variable I save all Project Objects first
func makeAnArrayFromResults<T>(object: T.Type) -> [T]?{
var array = [T]()
guard let mainArray = allRealmData else { return nil }
for i in mainArray {
if let object = i as? T {
array.append(object)
}
}
return array
}
then I would like to use Object Mapper to change this array to JSON Object, but when I try do it, I receive an error and don't know how can I resolve it. My second method looks like that:
func createJSON<T: Object>(object: T.Type){
let array = makeAnArrayFromResults(object)
let json = Mapper().toJSONString(array!, prettyPrint: true) //here error
}
error info: Cannot invoke "toJSONString" with an argument list of type"([T], prettyPrint: Bool)".
Do you have any sugestions how can I create JSON from Result in Realm?
Firstly, makeAnArrayFromResults<T> is really just map:
let someRealmResults: Results<Project>?
...
let array = someRealmResults?.map { $0 } // => [Project]?
As far as the Object Mapper integration goes, it looks like you don't have a toJSONString function defined that satisfies the first argument type constraints of [Person].
There's quite a bit of discussion in Object Mapper's issue tracker about interoperability with Realm that you may find useful: https://github.com/Hearst-DD/ObjectMapper/issues/475

Safe Dynamic JSON Casts In Swift

I suspect that I am not quite grokking Swift 1.2, and I need to RTFM a bit more.
I'm working on a Swift app that reads JSON data from a URI.
If the JSON data is bad, or nonexistent, no issue. The JSON object never instantiates.
However, if the JSON data is good JSON, but not what I want, the object instantiates, but contains a structure that is not what I'm looking for, I get a runtime error.
I looked at using Swift's "RTTI" (dynamicType), but that always returns "<Swift.AnyObject>", no matter what the data is.
I want the JSON to be a specific format: An array of Dictionaries:
[[String:String]]! JSON: [{"key":"value"},{"key","value"},{"Key":"value"}]
If I feed it a single element:
{"Key":"value"}
The routine I have tries to cast it, and that fails.
I want to test the JSON object to make sure that it has a structure I want before casting.
if(nil != inData) {
let rawJSONObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(inData, options: nil, error: nil)
println("Type:\(rawJSONObject.dynamicType)")
if(nil != rawJSONObject) {
// THE LINE BELOW BLOWS UP IF I FEED IT "BAD/GOOD" JSON:
let jsonObject: [[String:String]]! = rawJSONObject as! [[String:String]]!
// I NEED TO TEST IT BEFORE DOING THE CAST
if((nil != jsonObject) && (0 < jsonObject.count)) {
let jsonDictionary: [String:String] = jsonObject[0]
if("1" == jsonDictionary["semanticAdmin"]) { // We have to have the semantic admin flag set.
let testString: String! = jsonDictionary["versionInt"]
if(nil != testString) {
let version = testString.toInt()
if(version >= self.s_minServerVersion) { // Has to be a valid version for us to pay attention.
self.serverVersionAsInt = version!
}
}
}
}
}
}
My question is, is there a good way to test an NSJSONSerialization response for the structure of the JSON before uwinding/casting it?
I feel as if this question may be closer to what I need, but I am having trouble "casting" it to my current issue.
You can use safe unwrapping to test the type of your raw object, for example:
if let jsonObject = rawJSONObject as? [[String:String]] {
// jsonObject is an array of dictionaries
} else if let jsonObject = rawJSONObject as? [String:String] {
// jsonObject is a dictionary
// you can conform it as you wish, for example put it in an array
} else {
// fail, rawJSONObject is of another type
}
Currently, your code crashes because of the forced unwrapping, with !, of values that will be nil if the cast fails.

My data is being written to Firebase database but i can't read it why?

I'm new to swift and databases. All I'm trying to do is read from my firebase database. I'm using the example code provided here: https://www.firebase.com/docs/ios/guide/retrieving-data.html.
I'm calling this from my viewcontroller.swift file in override func viewDidLoad(){}
func getRootRef(){
// Read data and react to changes
println("entered getRootRef")
myRootRef.observeEventType(.Value, withBlock: { snapshot in
println("value1")
println(String(stringInterpolationSegment: snapshot.value))
println("value2")
}, withCancelBlock: { error in
println(error.description)
println("error")
})
println("left getRootRef")
}
Output:
entered getRootRef
left getRootRef
ViewController3
ViewController4
value1
(Function)
value2
I do not understand why "(Function)" is printing out instead of my data. both read and write permission are set to true. I am making a Mac app.
Your code sample doesn't give enough info as to what you want to do - however, assuming you want to print out the contents of the myRootRef node...
I believe that in Swift, FDataSnapshot.value is considered optional - it could contain a value or it could be nil. Therefore we need to unwrap the value:
myRootRef.observeEventType(.Value, withBlock: { snapshot in
println( snapshot.value()! )
})
The ! is a forced unwrap of the variable so it must contain a value. It should be checked for nil before printing or else it would cause a runtime error.
This may be safer
myRootRef.observeEventType(.Value, withBlock: { snapshot in
if let value: AnyObject = snapshot.value() {
println(value)
}
})
Note that snapshot.value could contain one of a number of different objects: Data types returned: * NSDictionary * NSArray * NSNumber (also includes booleans) * NSString