Error Domain=NSCocoaErrorDomain Code=3840 When JsonString parsing in Swift5 - ios

I'm getting a push message. It seems to be jsonString.
But this is not changed into jsonArray. What's the problem?
AppDelegate.swift
guard
let aps = data[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let body = alert["body"] as? String
else {
Log.Error("it's not good data")
return
}
let jsonStringData : Data = body.data(using: .utf8)!
Log.Info(jsonStringData)
do {
let jsonArray = try JSONSerialization.jsonObject(with: jsonStringData, options : .allowFragments) as? [Dictionary<String,Any>]
Log.Info(jsonArray) // use the json here
} catch let error as NSError {
Log.Error(error)
}
Value of body (String)
{
notification : {
"title" : "test title.",
"body" : "test context."
},
data : {
"image" : "http://11.111.111.111:100000000/_img/sample_01.jpg",
"page_url" : "http://11.111.111.111:100000000/test?address=",
"type" : "test"
}
}
The log of body is like this in JSON form. But this is not translated. I don't know what I'm missing.
**Error is : **
Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in
object around character 7." UserInfo={NSDebugDescription=No string key
for value in object around character 7.}

Thank you for #vadian and #Larme and #Sh_Khan and #Kamran
As you said, JSON was not valid. This should have been received by JSON. And as #Larme said, I didn't need options, I didn't need to set as. It rather showed me a warning.
It's worked
guard
let aps = data[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let body = alert["body"] as? String
else {
Log.Error("it's not good data")
return
}
let jsonStringData : Data = body.data(using: .utf8)!
Log.Info(jsonStringData)
do {
let json = try JSONSerialization.jsonObject(with: jsonStringData, options: [])
Log.Info(json) // use the json here
guard let jsonArray = json as? [String: Any] else {
return
}
Log.Debug(jsonArray)
Log.Debug(jsonArray["data"])
} catch let error as NSError {
Log.Error(error)
}

Related

JSON Parsing---> Could not cast value of type '__NSCFString' (0x1e5c38f90) to 'NSDictionary' (0x1e5c39bc0)

{"msgType":"UPDATE_S","macAddress":"2F-01-01-01-01-01","deviceName":"vMining","deviceType":"vSensor","groupId":"vMiningYo","param”:”truckDetail","value":"[{'TruckNo':1,'Status':'Moving to crusher','Speed':0,'CheckPointNumber':16,'CurrentLoad':346,'TirePressureIssueWheelNumber':0,'TirePressure':6,'Longitude':36.835072,'Latitude':-109.059769,'Altitude':1.0}]","valueDimension":"JSON","topic":"in/vMiningYo_ios/vMINING","_MessageGateway_TimeMilliseconds":1557471205646,"_MessageGateway_TimeSeconds":1557471205,"_MessageGateway_TimeISO8601":"2019-05-10T06:53:25.646Z","_MessageGateway_MessageClientType":"WS","_MessageGateway_Topic":"in/vMiningYo_ios/vMINING"}
I'm getting above json data in string format and i'm parsing with JSONSerialization like below method. I can able to print value data in console but how can i access inside values based on keys.
func recieveMessage(json:String){
guard let data = json.data(using: .utf16),
let jsonData = try? JSONSerialization.jsonObject(with: data),
let jsonDict = jsonData as? [String: Any],
let param = jsonDict["param"] as? String else {
return
}
if param == "truckDetail"{
print("VALUE:: \(jsonDict["value"]!)")
let truckData = jsonDict["value"]! as! [String:Any]
print(truckData)
print(truckData["Status"])
// if let truckData = jsonDict["value"] as? [String: Any]{
// print(truckData)
// }
}
}
Printing in Console:
VALUE:: [{'TruckNo':1,'Status':'Moving to crusher','Speed':0,'CheckPointNumber':16,'CurrentLoad':346,'TirePressureIssueWheelNumber':0,'TirePressure':6,'Longitude':36.835072,'Latitude':-109.059769,'Altitude':1.0}]
How can I print Status value in this Dictionary? Thanks in advance.
There are two major issues:
The object for key value is a String (apparently JSON). That's what the error clearly says.
But actually it's not valid JSON because JSON strings must be wrapped in double quotes, single quotes are not supported.
You need two extra steps: Replace the single quotes with double quotes and deserialize the JSON string separately.
And the object is an array. Either use a loop or get an item by index
let json = """
{"msgType":"UPDATE_S","macAddress":"2F-01-01-01-01-01","deviceName":"vMining","deviceType":"vSensor","groupId":"vMiningYo","param":"truckDetail","value":"[{'TruckNo':1,'Status':'Moving to crusher','Speed':0,'CheckPointNumber':16,'CurrentLoad':346,'TirePressureIssueWheelNumber':0,'TirePressure':6,'Longitude':36.835072,'Latitude':-109.059769,'Altitude':1.0}]","valueDimension":"JSON","topic":"in/vMiningYo_ios/vMINING","_MessageGateway_TimeMilliseconds":1557471205646,"_MessageGateway_TimeSeconds":1557471205,"_MessageGateway_TimeISO8601":"2019-05-10T06:53:25.646Z","_MessageGateway_MessageClientType":"WS","_MessageGateway_Topic":"in/vMiningYo_ios/vMINING"}
"""
let data = Data(json.utf8)
do {
if let result = try JSONSerialization.jsonObject(with: data) as? [String:Any],
let param = result["param"] as? String {
if param == "truckDetail" {
let value = result["value"] as! String
let valueString = value.replacingOccurrences(of: "\'", with: "\"")
let valueData = Data(valueString.utf8)
if let valueResult = try JSONSerialization.jsonObject(with: valueData) as? [[String:Any]] {
for item in valueResult {
print(item["Status"] as? String ?? "n/a")
}
}
}
}
} catch { print(error)}
jsonDict["value"] is a json string not a dictionary
let truckStr = jsonDict["value"] as! String
let jsonDic = try! JSONSerialization.jsonObject(with:Data(truckStr.utf8)) as! [String: Any]
print(jsonDic["Status"])

Swift 4 parse string to json object

I have implement qr code scanner, Where in "metadataOutput" delegate method I have received response which has key like "stringValue", Value of this key is
stringValue "'{ "part_number":"154100102232",
"lot_number":"03S32401701344"}'"
I want parse string value to json object, but I am not able to do that.
let data = stringValue.data(using: .utf8)!
do {
if let json = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [AnyHashable:Any]
{
print("Json:::",json)
// post a notification
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: "SCANNER_DATA"), object: nil, userInfo: json)
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
I have followed above approach to parse string to json, but I have found following error.
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around
character 0." UserInfo={NSDebugDescription=Invalid value around
character 0.}
Can anyone have any idea about this?
Better have an extension to String like this
extension String{
func toDictionary() -> NSDictionary {
let blankDict : NSDictionary = [:]
if let data = self.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
} catch {
print(error.localizedDescription)
}
}
return blankDict
}
}
Use like this
let dict = stringValue.toDcitionary()
Or you can use pod for all these kind of work from UtilityKit on github https://github.com/utills/UtilityKit
This works with me , You string has ' character around trailing "' content '"
let stringValue = """
{"part_number":"154100102232","lot_number":"03S32401701344"}
"""
let data = stringValue.data(using: .utf8)!
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String:Any]
{
print("ewtyewytyetwytewytewtewytew",json)
} else {
print("ewtyewytyetwytewytewtewytew","bad json")
}
} catch let error as NSError {
print("ewtyewytyetwytewytewtewytew",error)
}

How can I parse this JSON object using Swift 3.0

I'm trying to parse a JSON string returned from a new API. The returned JSON string looks like this.
QuerySearchResult":{
"StartAt":"1",
"Count":"40",
"TotalAvailable":"500",
"Items":[
{"TITLE":"OST420 Generation",
"PATH":"http:\\Test.pdf",
"WRITE":"2016-12-12T15:47:42",
"RANK":"32286574",
"SIZE":"145091",
"ISDOCUMENT":"true",
"ID":"18548",
"WPTASK":"Onsite Generation",
"WPDOCTYPE":"Local Operating Procedure",
"WPDOCREFID":"304580",
"WPCONTENTTYPE":"Document"},
{"TITLE":"OST420 Measurement",
"PATH":"http:\Test33.pdf",
.
.
I'm using the code below which accepts the JSON variable but fails when I try to load item. I've tried using Array around Dictionary but it still fails. What declaration do I need to read in Items?
if let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as? Dictionary<String, AnyObject> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
if let items = json["Items"] as? Array<Dictionary<String, AnyObject>> {
for rec in items {
if let title = rec["TITLE"] as? String {
let xx = title
}
}
}
}
}
First of all you are not correctly iterating through Dictionary also instead of looping through Dictionary for accessing single value, try by directly accessing it through subscripting and the proper JSON notation of Dictionary in Swift 3 is [String : Any].
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String : Any],
let queryDic = json["QuerySearchResult"] as? [String : Any],
let items = queryDic["Items"] as? [[String : Any]] {
for item in items {
if let title = item["TITLE"] as? String {
print(title)
}
}
}
In Swift 3.1 :-
func parseJson(anyObj:AnyObject) {
if let anyObj = anyObj as? Array<Dictionary<String,AnyObject>> {
self.yourArrayName = anyObj.flatMap({yourModelName(json:$0) })
}
}
The Json returns the data into the dictionary and array format, so treat the json data like it, it makes you easier to understand.
Data in braces '{' and '}' is dictionary.
and Data in braces '[' or ']' is array.
Now start parsing the json data by the dictionary and array properties it exactly works. Or for confirmation print your json data.
Use SwiftyJSON : which can simply and easily parse the JSON more than your code.
So, how do we parse using that?
First get your response as Data()
let jsonData = JSON(data: results!)
Then here how we parse that JSON.
import Foundation
import SwiftyJSON
enum JSONParseError : ErrorType {
case UnknownField
case EmptyJSON
}
extension JSONParseError : CustomStringConvertible {
var description: String {
switch self {
case .UnknownField:
return "Error when parsing json because there is no field"
case .EmptyJSON:
return "Error when parsing empty json"
}
}
}
guard let querySearchResult : [String : JSON] = jsonData["QuerySearchResult"].dictionary else{
throw JSONParseError.UnknownField
}
guard let startAt : String = querySearchResult["StartAt"].string else{
throw JSONParseError.UnknownField
}
guard let count : String = querySearchResult["Count"].string else{
throw JSONParseError.UnknownField
}
guard let totalAvailable : String = querySearchResult["TotalAvailable"].string else{
throw JSONParseError.UnknownField
}
guard let items : [JSON] = querySearchResult["Items"].array else{
throw JSONParseError.UnknownField
}
if items.count > 0 {
for i in 0 ..< items.count{
guard let title = items[i]["TITLE"].string else{
throw JSONParseError.UnknownField
}.... //So On
}
}else{
throw JSONParseError.EmptyJSON
}

pull data from parsed Json with swift

I want to get my CampaignList from JsonObject which I parsed before. But it gives fatal error while it is running.
Error
"fatal error: unexpectedly found nil while unwrapping an Optional value"
self.CampaignArray = Campaigns as! NSMutableArray
The code :
var CampaignArray:NSMutableArray = []
func Get(){
let res: String = ""
let jsonObject = ["PhoneNumber": "xxxxx"]
let Jsn = JsonClass(value: jsonObject, text: res)
Alamofire.request(.POST, "http://MYURL",parameters: jsonObject,
encoding: .JSON).validate(statusCode: 200..<303)
.validate(contentType: ["application/json"])
.responseJSON { (response) in
NSLog("response = \(response)")
switch response.result {
case .Success:
guard let resultValue = response.result.value else {
NSLog("Result value in response is nil")
//completionHandler(response: nil)
return
}
let responseJSON = resultValue
print(responseJSON)
let result = Jsn.convertStringToDictionary(responseJSON as! String)!
print("result: \(result)")
let Campaigns = (result as NSDictionary)["Campaigns"]
print(Campaigns)
self.CampaignArray = Campaigns as! NSMutableArray
let notifications = (result as NSDictionary)["Notifications"]
print(notifications)
break
case .Failure(let error):
NSLog("Error result: \(error)")
// Here I call a completionHandler I wrote for the failure case
return
}
}
}
And my response Json is:
json: {"CampaignList":[
{"Bonus":"5","CampaignId":"zQUuB2RImUZlcFwt3MjLIA==","City":"34"}
{"Bonus":"3","CampaignId":"VgYWLR6eL2mMemFCPkyocA==","City":"34"}],
"MemberId":"ZBqVhLv\/c2BtMInW52qNLg==",
"NotificationList":[{"Notification":"Filiz Makarnadan Milli Piyango Çekiliş Hakkı Kazanmak İster misin ?","PhoneNumber":"555555555"}]}
JSON you provide is invalid. There is lack of , in Campaigns dictionary.
Valid JSON looks like:
{
"CampaignList": [
{
"Bonus": "5",
"CampaignId": "zQUuB2RImUZlcFwt3MjLIA==",
"City": "34"
},
{
"Bonus": "3",
"CampaignId": "VgYWLR6eL2mMemFCPkyocA==",
"City": "34"
}
],
"MemberId": "ZBqVhLv/c2BtMInW52qNLg==",
"NotificationList": [
{
"Notification": "Filiz Makarnadan Milli Piyango Çekiliş Hakkı Kazanmak İster misin ?",
"PhoneNumber": "555555555"
}
]
}
fatal error: unexpectedly found nil while unwrapping an Optional value
You receive this error because you try cast nil to NSDictionary object.
You have no Campaigns key in JSON you provide, so when you try to get this key from JSON you get nil. In next step you try cast this nil to NSDictionary.
Try use CampaignList key to get data you want.
let result: [String: AnyObject] = Jsn.convertStringToDictionary(responseJSON as! String)!
let campaigns: [Campaign] = result["CampaignList"] as! [Campaign]
print(Campaigns)
self.CampaignArray = campaigns
let notifications = result["NotificationList"]
print(notifications)
The same case will be with your Notifications key from JSON Dictionary.
You should also use swift types over objective-c NSDictionary and NSArray.
Try to use SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON)
This library (pod) is very simple and has detailed documentation.
Your example:
I put son file "data.json" in my project and read it. Thank Daniel Sumara for your json example correction.
if let path = NSBundle.mainBundle().pathForResource("data", ofType: "json") {
if let data = NSData(contentsOfFile: path) {
let json = JSON(data: data)
if let CampaignList = json["CampaignList"].array {
for index in 0 ..< CampaignList.count {
print("Campaign [\(index)]")
if let CampaignId = CampaignList[index]["CampaignId"].string {
print(" CampaignId: \(CampaignId)")
}
if let City = CampaignList[index]["City"].string {
print(" City: \(City)")
}
if let Bonus = CampaignList[index]["Bonus"].string {
print(" Bonus: \(Bonus)")
}
}
}
if let MemberId = json["MemberId"].string {
print("MemberId: \(MemberId)")
}
if let NotificationList = json["NotificationList"].array {
print("NotificationList")
for notification in NotificationList {
if let Notification = notification["Notification"].string {
print(" Notification: \(Notification)")
}
if let PhoneNumber = notification["PhoneNumber"].string {
print(" PhoneNumber: \(PhoneNumber)")
}
}
}
}
}
Also you can use Alamofire-SwiftyJSON (https://github.com/SwiftyJSON/Alamofire-SwiftyJSON)
P.S. you have fatal errors because you do not check if value is nil. read about "if let" expression (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html)

parsing JSON with Swift

I'm coming from android programming to Swift iOS programming and have a hard time parsing a json
here's String I try to parse :
{"response":[{"uid":111,"first_name":"someName","last_name":"someLastName","photo_100":"http:someUrl/face.jpg"}]}
here how I try to parse this :
if let dict = Utils.convertStringToDictionary(response)! as? [String: AnyObject]{
// this part is yet doing ok
if let response = dict["response"] as? [String: AnyObject]{
NSLog("let response \(response)")
if let first_name = response["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
else {
NSLog("not an []")
}
the Log message gives me "not an []" as it can't make a response object. As far as I understand, I'm doing right as [String: AnyObject] is what is in "response" body of my json
Just in case, here's my Utils.convertStringToDictionary method:
public static func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers) as? [String:AnyObject]
return json
} catch {
NSLog("Something went wrong")
}
}
return nil
}
Array in swift denotes with []
Dictionary in swift denotes with [:]
your response parameter is array of dictionary ... so it denotes with [[:]]
so just parse it with [[String: AnyObject]]
if let response = dict["response"] as? [[String: AnyObject]]{
for user in response{
NSLog("let response \(user)")
if let first_name = user["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
}
Problem here is response is an array
if let response = dict["response"] as? NSArray{
for value in response as? NSDictionary{
print(value["uid"]) /// prints 111
print(value["first_name"]) /// prints someName
}
}
Try this code
if let dict = Utils.convertStringToDictionary(response)! as? [String: AnyObject]{
// this part is yet doing ok
if let response = dict["response"] as? NSArray{
NSLog("let response \(response)")
for dict in response{
if let first_name = dict["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
}
else{
NSLog("not an []")
}
}

Resources