AlamoFire 4.0 + SwiftyJSON Unwrapping deeply nested JSON - 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"])
}

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

Save JSON Response as Variable to Deserialise with SwiftyJSON

I'm going to use either SwiftyJSON or EasyFastMapping to deserialise JSON data into variables and constants but I'm not sure on how to save the whole JSON file into its own object, if it is even possible.
I will be using Alamofire to handle the GET request and pull the JSON data down, is it possible to do it like this?
How I want it to work:
1. Alamofire pulls down the JSON data
Alamofire puts the data into an object
SwiftyJSON accesses the downloaded data and allows me to put individual parts of the data into separate variables and constants.
You could take a look at the documentation for SwiftyJSON and Alamofire and you will find plenty of examples.
From Alamofire Readme:
Alamofire.request("https://httpbin.org/get").responseJSON { response in
debugPrint(response)
if let json = response.result.value {
print("JSON: \(json)")
}}
From SwiftJSON Readme:
let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string {
//Your implementation here
}
You can also create a separate response object and deserialize all the response JSON into the object. Also take a look at the built-in JSONSerialization API in the Foundation framework.

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

Swift 2.0 How to parse JSON?

I am coding a hangman game and am loading the possible words into my app using json text files. I tried to follow the examples of others on this website but I am getting errors from Xcode.
I tried the following code based on another answer:
import Foundation
var error: NSError?
let jsonData: NSData = /* get your json data */
let jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as NSDictionary
But I got an errors on line 4 with jsonDict that said "call can throw but is not marked with try, and the error is not handled" and "Type JSONReadingOptions does not conform to protocol NilLiteralConvertible".
Here is the JSON File I would like to parse:
{
“wordList” : {
“difficulty” : “Easy”
“list” : [
“fireplace”,
“apple”,
“january”,
“tooth”,
“cookies”,
“mysterious”,
“essential”,
“magenta",
“darling”,
“pterodactyl”
]}}
I would like to be able to go into my list array and get values. Thank you very much for any help!
In Swift 2 you need to use the new error handling API instead of passing a reference to an NSError:
do {
let jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions(rawValue: 0)) as? NSDictionary
if let jsonDict = jsonDict {
// work with dictionary here
} else {
// more error handling
}
} catch let error as NSError {
// error handling
}
You also can't pass nil as value to the options parameter, you need to pass a value of type NSJSONReadingOptions.
That said, the most common approach for parsing JSON in Swift is currently using third party libraries, such as Argo because they can save you a lot of code that is necessary to validate and safely cast the content of your JSON data to the correct Swift types.

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.