swift parsing JSON data - json

so am trying to learn about JSON parsing, i want to extract some information from these fields..
index = 90;
property1 = {
href = "http://www.bodybuilding.com/exercises/detail/view/name/supine-one-arm-overhead-throw";
text = "Supine One-Arm Overhead Throw";
};
property2 = {
href = "http://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/13/muscle/abdominals";
text = Abdominals;
};
property3 = (
{
href = "http://www.bodybuilding.com/exercises/detail/view/name/supine-one-arm-overhead-throw";
src = "http://www.bodybuilding.com/exercises/exerciseImages/sequences/839/Male/m/839_1.jpg";
text = "";
},
i can get a chunk of data, the problem is when i try to sort this information out... here is my code
func parseDictionary(dictionary: [String: AnyObject]) {
if let array: AnyObject = dictionary["results"] {
for resultDict in array as![AnyObject] {
if let resultDict = resultDict as? [String:AnyObject] {
if let wrapperType = resultDict["wrapperType"] as? String {
if let kind = resultDict["kind"] as? String {
print("wrapperType: \(wrapperType), kind: \(kind)")
}
}
} else {
print("expected a dictionary")
}
}
} else {
print("expected results array")
}
}
the error am getting is..
//Could not cast value of type '__NSCFDictionary' (0x1014c8a60) to //'NSArray' (0x1014c8470).

Your line:
for resultDict in array as![AnyObject] {
Needs to change to
for resultDict in array as![String: AnyObject] {
[AnyObject] is shorthand for Array<AnyObject>, whereas [String: AnyObject] is shorthand for Dictionary<String, AnyObject>, which explains your error.

Related

Reading from JSON file in Swift

I'm trying to read a JSON file but I keep getting an error when I try to read the "ParsedText". First I convert the serialized JSON data to a dictionary of type [String: Any] and then I try to read the dictionary["ParsedResults"] value and convert that to a dictionary of type [String: Any] but it always fails.
Here is the JSON file:
{
ErrorDetails = "<null>";
ErrorMessage = "<null>";
IsErroredOnProcessing = 0;
OCRExitCode = 1;
ParsedResults = ( {
ErrorDetails = "";
ErrorMessage = "";
FileParseExitCode = 1;
ParsedText = "Sample text";
TextOverlay = {
HasOverlay = 0;
Lines = ( );
Message = "Text overlay is not provided as it is not requested";
};
} );
ProcessingTimeInMilliseconds = 869;
SearchablePDFURL = "Searchable PDF not generated as it was not requested.";
}
Here is part of the swift function:
do {
//create json object from data
let dictionary = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: Any]
for (key, value) in dictionary {
print("KEY: \(key)")
print("VALUE: \(value)")
}
let parsedResults = dictionary["ParsedResults"] as! [String: Any]
print("parsedResults: \(parsedResults)")
} catch let error {
print("ERROR: Could not serialize jSON Data: \(error.localizedDescription)")
}
}
As already commented, your said-to-be JSON file is not in JSON format.
It seems to be in a classic text-based plist format. If you do want to read the file as is, you can use PropertyListSerialization:
import Foundation
let data = """
{
ErrorDetails = "<null>";
ErrorMessage = "<null>";
IsErroredOnProcessing = 0;
OCRExitCode = 1;
ParsedResults = ( {
ErrorDetails = "";
ErrorMessage = "";
FileParseExitCode = 1;
ParsedText = "Sample text";
TextOverlay = {
HasOverlay = 0;
Lines = ( );
Message = "Text overlay is not provided as it is not requested";
};
} );
ProcessingTimeInMilliseconds = 869;
SearchablePDFURL = "Searchable PDF not generated as it was not requested.";
}
""".data(using: .utf8)
do {
//create property list object from data
let dictionary = try PropertyListSerialization.propertyList(from: data!, options: [], format: nil) as! [String: Any]
for (key, value) in dictionary {
print("KEY: \(key)")
print("VALUE: \(value)")
}
let parsedResults = dictionary["ParsedResults"] as! [[String: Any]] //<- See Larme's comment.
print("parsedResults: \(parsedResults)")
} catch let error {
print("ERROR: Could not deserialize plist Data: \(error.localizedDescription)")
}
But I recommend you to check the part generating such files, and fix it to generate a valid JSON file.

how to do safe json parsing in swift?

I am getting a Json of images from sever i have created one modal class & under which i have declared images as member of that class.
class SomeClass: NSObject {
var objImages:[Images] = [Images]()
}
Images as class
class Images {
var thumbImage:String = ""
var fullImage:String = ""
init(dictionary:NSDictionary){
fullImage = dictionary["thumb"] as? String ?? ""
thumbImage = dictionary["full_url"] as? String ?? ""
}
init() {
}
}
Parsing the json data
if let arrImg = dictionary["images"] {
for value in arrImg as! NSArray {
let tempImage:Images = Images(dictionary: value as! NSDictionary)
recipeImages.append(tempImage)
}
}
below is the josn response
{ "images": [
{
"thumb": "https://mysevrer.com/v0/b/a.png”,
"full_url": "https://mysevrer.com/v0/b/b.png"
},
{
"thumb": "https://mysevrer.com/v0/b/a.png”",
"full_url": "https://mysevrer.com/v0/b/b.png”"
}
]
}
Please is it safe way to parse response ?
What if i don'tget image as array
What if i don't get the "thumb"
& "full" as keys
I'm not sure if this is what you mean, but this will return an optional instance of Images. So it will return nil if the dictionary doesn't contain one or both of those keys.
class Images {
var thumbImage:String
var fullImage:String
init?(dictionary:Dictionary<String,String>){
guard let image = dictionary["thumb"] else { return nil }
guard let thumb = dictionary["full_url"] else { return nil }
self.fullImage = image
self.thumbImage = thumb
}
}
For the parsing part of the array.
guard let imagesArray = dictionary["images"] as? Array<Dictionary<String,String>> else { return }
for dict in imagesArray {
guard let images = Images(dictionary: dict) else { continue }
recipeImages.append(images)
}

Swift: How to Parse JSON Facebook graph data for group members

How can I parse this JSON into an array of dictionaries - [String: AnyObject]?
typealias FBUser = [String: AnyObject]
var fbGroup = [FBUser]()
func logUserGroup() {
let graphRequest = FBSDKGraphRequest(graphPath: "88##########6270/members", parameters: ["fields": "id, name"], HTTPMethod: "GET")
graphRequest.startWithCompletionHandler { (connection, result, error) -> Void in
if error != nil {
print(error)
} else {
if let resultdict = result as? [NSDictionary] {
for member in resultdict {
var user = FBUser()
if let idvalue = member["id"] as? String {
user["id"] = idvalue
}
if let name = member["name"] as? String {
user["name"] = name
}
self.fbGroup.append(user)
}
}
}
}
}
Facebook JSON:
{
data = (
{
id = 102055#####10000;
name = "Kristian";
},
{
id = 10208######08475;
name = "Oren";
},
{
id = 1020#######57409;
name = "Ron";
}
};
}
If there is a good resource for different parsing techniques that would be very helpful.

Swift: JSON is nil when accessing NSDictionairy

When I print(JSON) I get the files, so the .request works.
But when I am trying to access the "test" key (which exists) I get nil
I get
"I am here"
"now ,I am here"
Alamofire.request(.GET, self.APIBaseUrl , parameters: ["api_key": self.APIkey])
.responseJSON { response in
if let JSON = response.result.value {
print("I am here")
if let str = JSON as? NSDictionary {
print("now , I am here")
if let movieUrlString = str["poster_path"] as? String)! {
print("but now here")
}
EDITED
print(dict)
**dates** = {
maximum = "2015-10-21";
minimum = "2015-09-30";
};
page = 1;
**results** = (
{
adult = 0;
"poster_path" = "/2XegKZ0I4QrvzpEHneigRk6YTB1.jpg";
++(more results)
Try to use more meaningful debug printing statements and variables names. Also you were not using the right variable for subscripting. Fixed example:
Alamofire.request(.GET, self.APIBaseUrl , parameters: ["api_key": self.APIkey]).responseJSON { response in
if let JSON = response.result.value {
print("inside JSON result")
if let dict = JSON as? NSDictionary {
print("inside decoded JSON")
if let results = dict["results"] as? [NSDictionary] {
for result in results {
if let movieUrlString = result["poster_path"] as? String {
print(movieUrlString)
}
}
}
}
}
}

How can I convert a Realm object to JSON in Swift?

I have two Realm tables declared:
class Task: Object {
dynamic var taskID: String = ""
let taskAssignedTo = List<Contacts>()
}
class Contacts: Object {
dynamic var contactEmail: String = ""
dynamic var contactName: String = ""
}
Final goal is to convert the Task Realm object into JSON. The method I'm thinking of is:
Convert the object to a dictionary using a method within the class
func taskToDictionary() -> [String: AnyObject] {
return [
"taskID" : self.taskID,
"taskAssignedTo" : self.taskAssignedTo._rlmArray.count //Not sure how to get the array
]
}
Convert the resulting dictionary into JSON with SwiftyJSON
let taskObject = Task()
let newTaskJSON = JSON(taskObject.taskToDictionary())
Right now, this converts ok, but:
Is there a better way to do this?
How can I convert the RLMArray into an array for JSON conversion?
Managed to find the answer here:
Can I serialize a RealmObject to JSON or to NSDictionary in Realm for Swift?
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let objectClassName = prop.objectClassName {
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
if let object = nestedListObject._rlmArray[index] as? Object {
objects.append(object.toDictionary())
}
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
}
return mutabledic
}
}
Update for Xcode 7 & Swift 2:
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
return mutabledic
}
}
Update to Xcode 8 and Swift 3 :
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
As i can't comment, #Eric
Based on #Eugene Teh answer
I had to do a specific treatment for date. Here is my code (swift 3)
I get the value first
if let value = self.value(forKey: props.name) {
if props.type == .date {
mutabledic[props.name] = (value as! Date).timeIntervalSince1970
//for using like the example, this should work
//mutabledic.setObject( (value as! Date).timeIntervalSince1970, forKey: prop.name as NSCopying)
}
[..]//other case
}
Swift 4.2 Xcode 11
This is how i solved the issue. To covert Realm Objects into JSON Array for sending to the Rest APIs
Requirement - SwiftyJSON
func getJsonArray(){
var dicArray = [Dictionary<String,AnyObject>]()
for item in cartsData! {
dicArray.append(item.toDictionary())
}
print(JSON(dicArray))
}
cartsData - var cartsData : Results<...>?
extension Object {
func toDictionary() -> [String:AnyObject] {
let properties = self.objectSchema.properties.map { $0.name }
var dicProps = [String:AnyObject]()
for (key, value) in self.dictionaryWithValues(forKeys: properties) {
//key = key.uppercased()
if let value = value as? ListBase {
dicProps[key] = value.toArray1() as AnyObject
} else if let value = value as? Object {
dicProps[key] = value.toDictionary() as AnyObject
} else {
dicProps[key] = value as AnyObject
}
}
return dicProps
}
}
extension ListBase {
func toArray1() -> [AnyObject] {
var _toArray = [AnyObject]()
for i in 0..<self._rlmArray.count {
let obj = unsafeBitCast(self._rlmArray[i], to: Object.self)
_toArray.append(obj.toDictionary() as AnyObject)
}
return _toArray
}
}