Error while parsing JSON "Unescaped control character around character 981" - ios

Error Domain=NSCocoaErrorDomain Code=3840 "Unescaped control character
around character 981." UserInfo={NSDebugDescription=Unescaped control
character around character 981.}
I am getting the above error in response to a request.
Below are the lines of code:
Alamofire.request(.POST, urlStr, parameters: parameter, encoding: .JSON, headers: nil).validate().responseJSON {
response in switch response.result {
case .Success(let JSON):
completionHandler(JSON as! NSDictionary)
case.Failure(let Error):
print(Error)
}
}
It gives a JSON response in Postman.
The response which is I am getting in Postman:
{
"orderdetails": {
"status_code": "200",
"status_message": "Order details",
"billingandshipping": {
"billing": {
"firstname": "first",
"lastname": "last",
"email": "aa#bbb.com",
"address": "dasdesfrew",
"city": "Rajkot",
"area": "University Road",
"pincode": "360003",
"phone": "1234567890",
"mobileno": "1234567891"
},
"shipping": {
"firstname": "first",
"lastname": "last",
"email": "aa#bbb.com",
"address": "dasdesfrew",
"city": "dasdesfrew",
"area": "dcdc",
"pincode": "360003",
"phone": "1234567890",
"mobileno": "1234567891"
}
},
"orders": [
{
"order_id": "77",
"order_date": "09-08-2016 13:05:29",
"delivery_date": "10-08-2016",
"order_items": [
{
"Sr": "1",
"product_name": "Lemon",
"gujtitle": "લીંબુ ",
"product_code": "000057",
"product_price": "108.00",
"product_qty": "2",
"unit": "1 kg.",
"product_total": "216"
}
],
"final_total": "216.00",
"shipping_cost": "0.00",
"order_total": "216.00",
"discount_type": "null",
"discount_amount": "null",
"coupon_name": "null",
"comment": "gdhdj\nfghd.g\nghj\n\n\n\n\n\n\n\n\n\n.."
}
]
}
}

As per you were told, there is a problem related to "\n".
So I suggest you can add "" which will work for you, like below:
"\n"=> "\\n"
Because this is a special character called a backspace character.

Since Swift 5, instead of manually adding another \ to your otherwise valid \n in a JSON string, you could simply declare it as a raw string literal, using this syntax:
let jsonString = #"{"comment": "gdhdj\nfghd.g\nghj\n\n\n\n\n\n\n\n\n\n.."}"#
Multiline works too:
let jsonString = #"""
{
"comment": "gdhdj\nfghd.g\nghj\n\n\n\n\n\n\n\n\n\n.."
}
"""#
While the above would compile fine if using just """ (without the #), in runtime it would throw an error in the example below with JSONSerialization, which is fixed by #""":
do {
guard let data = jsonString.data(using: .utf8) else { throw SomeError() }
let obj = try JSONSerialization.jsonObject(with: data)
print("valid!")
} catch {
print(error)
}

NSLog the NSData that you received and have a look what you find around byte 981. The thing with unescaped control characters is that they are invisible, so you can't see them in an NSString, but you'll see them in the NSData.
If your data has length 981 bytes or very close then there's a chance that your code processed incomplete JSON data which will almost always fail; that's something you need to fix. If there is a control character between some items (say between two array elements) then this might be a bug in the server code.

I spent some time to figure out what 49546 was.
If your issue is Unescaped control character around character 49546, replace \t with \\\t.

To be sure (as people make foul copy/paste...), I build my object safe:
...
private final func fillWith(
id: Int,
name: String?
) {
self.id = id
self.productName = name?.replacingOccurrences(of: "\t", with: "")
self.productName = self.productName?.replacingOccurrences(of: "\n", with: "")
So no problem when sending up.

Related

JSONDecoder can't decode Array but can decode String

I have a struct that I would like to parse from Json:
struct Subsidiary: Decodable {
let id: Int?
let subsidiary_ref: String?
let name: String?
let address: String?
}
I try to parse it like:
let sub: [Subsidiary] = try! JSONDecoder().decode([Subsidiary].self, from: data)
where data is Data type from
session.dataTask(with: urlRequest) { (data, response, error) in
and it gives me an error
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a string/data instead.", underlyingError: nil))
If I do it like this:
let sub: String = try! JSONDecoder().decode(String.self, from: data)
it works and it gives me son
[
{"id": 5913, "subsidiary_ref": "0000159", "name": "Mercator Hipermarket Koper", "address": "Poslov.98-Koper,Dolinska C", "city": "Koper", "coordinates_x": null, "coordinates_y": null, "phone_number": "+386 56-636-800", "frequency": "A", "channel": "Food", "subchannel": "Hypermarket", "customer": 7, "day_planned": true, "badge_visible": true, "open_call": true, "number_of_planned": 13, "number_of_calls": 22, "last_call_day": 3, "notes": " notesi ki ne smejo nikoli zginiti bla marko bdsa"},
{"id": 5870, "subsidiary_ref": "0000773", "name": "Kompas Shop Pe Ferneti?i", "address": "Partizanska 150", "city": "Se?ana", "coordinates_x": null, "coordinates_y": null, "phone_number": "+386 57-380-636", "frequency": "A", "channel": "Food", "subchannel": "Supermarket", "customer": 17, "day_planned": true, "badge_visible": true, "open_call": true, "number_of_planned": 13, "number_of_calls": 1, "last_call_day": 1, "notes": null},...
]
What is wrong with my code?
EDIT:
I figure out, that if I create a string variable, and then convert this string value to data it works even with Subsidiary struct.
So something should be wrong with the data variable.
The fact that you can decode a String.self and get your JSON printed means that the root of the JSON is a string. The JSON you got, in text form, probably looks like this:
"[\r\n {\"id\": 5913, \"subsidiary_ref\": \"0000159\", \"name\": \"Mercator Hipermarket Koper\", \"address\": \"Poslov.98-Koper,Dolinska C\", \"city\": \"Koper\", \"coordinates_x\": null, \"coordinates_y\": null, \"phone_number\": \"+386 56-636-800\", \"frequency\": \"A\", \"channel\": \"Food\", \"subchannel\": \"Hypermarket\", \"customer\": 7, \"day_planned\": true, \"badge_visible\": true, \"open_call\": true, \"number_of_planned\": 13, \"number_of_calls\": 22, \"last_call_day\": 3, \"notes\": \" notesi ki ne smejo nikoli zginiti bla marko bdsa\"}\r\n]"
Note that the actual JSON you want is put in ""s, so all the special characters are escaped.
The web service has given the JSON in a very weird way...
To get the actual JSON data decoded, you need to get the string first, then turn the string into Data, then decode that Data again:
// nil handling omitted for brevity
let jsonString = try! JSONDecoder().decode(String.self, from: data)
let jsonData = jsonString.data(using: .utf8)!
let sub = try! JSONDecoder().decode([Subsidiary].self, from: jsonData)
Of course, the best solution is to fix the backend.

how to check the json response array contains the substring

how to assert the json response array contains a substring in a string value.
I have tried this but assertion is failed response.then().body("response.content.Date", Matchers.everyItem(contains("2019-03") ));
my response body is
{
"response": {
"totalSize": 2,
"content": [
{
"requestId": " 931-f8222e",
"name": "gowtham",
"date": "2019-03-06",
"issue": "i have a cause"
},
{
"requestId": " 931-f8222e",
"name": "tharun",
"date": "2019-03-09",
"issue": "has a issue in billing"
}
]
}
}
i want to get all the records in the month(value) and assert the response showing data for given month
I found the solution. You were very close. Instead of using contains which matches full string, you can use containsString to match a substring.
Code:
response.then().body("response.content.date", Every.everyItem(Matchers.containsString("2019-03")));

How to consume an API response with Swift

I am trying to make an API request to get an API response I am getting all the elements but I am facing braces issue I want a whole response and "order_devices" key, in {} braces but I am getting these in [] braces.
the array in which i am passing value,
var popUpArray :[[String:AnyObject]] = []
then on btn click i am saving values in dictionary
#IBAction func btnSave(_ sender: Any) {
let popupDict = (["quantity": Int(txtEnterQuantity.text!), "name": lblDeviceName.text,"id": deviceDict["id"], "region":1, "system_integrated":1 ])as! [String:AnyObject]
and then passing the same dictionary value as parameter
let passDict = [
"dealer_id":dropDownId!,
"client_id":dropDownId!,
"distributor_id":searchBarId!,
"emp_id":UserId,
"comments":CommentKey!,
"accepted_by":0,
"valid_from":strDate!,
"valid_upto": 0,
"order_devices":popupDict
] as [String : Any]
if Reachability.isConnectedToNetwork() {
showActivityIndicator()
Alamofire.request("http://13.232.230.41/IAC_CRM/public/api/createOrder", method: .post, parameters: passDict, encoding: JSONEncoding.default, headers: [:])
.responseJSON { (response) in
i am getting this response ,
[
"comments": "demo",
"dealer_id": 3,
"valid_from": "6-3-2019",
"distributor_id": 72,
"client_id": 3,
"accepted_by": 0,
"emp_id": 33,
"valid_upto": 0
"order_devices":
[
[
"id": 1,
"quantity": 10,
"region": 1,
"system_integrated": 1
]
,
[
"id": 2,
"quantity": 12,
"region": 1,
"system_integrated": 1
]
]
]
i want this response,
{ "dealer_id":"1", "client_id":"2", "distributor_id":"2",
"emp_id":"1", "comments":"IAC test device comments", "accepted_by":0,
"valid_from":"2019-01-24", "valid_upto":"1", "order_devices":[
{
"device_id":"1",
"quantity":"1", "region":1, "system_integrated":1
}
,
{
"device_id":"2",
"quantity":"1"
"region":1,
"system_integrated":1
}
] }
means i want whole response and "order_devices" key in "curly braces"{} .
There is nothing wrong with request or response, your are getting response what your API is returning, You should ask you backend developer Or Api Provider to Give you response in form of your requirement i mean proper formatted Right now its in form of Array.

Received json data is in form of 531 bytes and giving curruptedData error in swift 4.1 and Xcode 9.2

I am trying to get response from server which is in form of JSON with Swift 4.1 and Xcode 9.2. But the received JSON data by JSONDecoder is printing 531 bytes and giving error
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))
my request task is
let itemUrl = URL(string: mainUrl.MainUrl + "viewallstore")
let foodUrl = URLRequest(url: itemUrl!)
URLSession.shared.dataTask(with: foodUrl) { (data, response, error) in
print(data ?? "Errrrr")
if data != nil {
do {
let storeDetails = try JSONDecoder().decode(AllStores.self, from: data!)
for store in storeDetails.StoreDetails {
self.foods.append(FoodCourt(storeId: store.str_id, storeNo: store.str_number, storeName: store.str_name, storePhone: store.str_phone, storeParking: store.str_parking, storeOpenTime: store.str_open_time, storeCloseTime: store.str_close_tie, storeStartdate: store.str_open_date, storeCloseDate: store.str_close_date, storeLogoPath: store.str_logo_path, storeLogoFileName: store.str_logo_file_name, storeStatus: store.status, storeCategory: store.str_cat, createdAt: store.create_at, storeZone: store.str_zone, storeAvailability: store.str_availability, storeMulCategory: store.str_multiple_cat))
}
}catch let error {
self.toastNeck(message: "\(error)")
print(error)
DispatchQueue.main.async{
myActivityIndicator.stopAnimating()
myActivityIndicator.hidesWhenStopped = true
}
}
DispatchQueue.main.async {
self.collectionViewFoodCourt.reloadData()
}
}
}.resume()
}
and my struct is
struct AllStores: Decodable{
let StoreDetails: [StoreDetail]
}
struct StoreDetail: Decodable {
let str_id: String
let str_number: String
//let tid : String? //tid
let str_name: String
let str_phone: String
let str_parking: String
let str_open_time: String
let str_close_tie: String
let str_open_date: String
let str_close_date: String
let str_logo_path: String
let str_logo_file_name: String
let status: String
let str_cat: String
let create_at: String
let str_zone: String
let str_availability: String
let str_multiple_cat: String
enum CodingKey: String {
case str_id = "str_id"
case str_number = "str_number"
//case tid = "tid"
case str_name = "str_name"
case str_phone = "str_phone"
case str_parking = "str_parking"
case str_open_time = "str_open_time"
case str_close_tie = "str_close_tie"
case str_open_date = "str_open_date"
case str_close_date = "str_close_date"
case str_logo_path = "str_logo_path"
case str_logo_file_name = "str_logo_file_name"
case status = "status"
case str_cat = "str_cat"
case create_at = "create_at"
case str_zone = "str_zone"
case str_availability = "str_availability"
case str_multiple_cat = "str_multiple_cat"
}
}
and my json file on server is
{
"StoreDetails": [
{
"str_id": "1",
"str_number": "0",
"tid": "",
"str_name": "Moti mahal",
"str_des": "",
"str_phone": "9540011581",
"str_add": "",
"str_parking": "Ground Floor",
"str_short_dis": "Moti Mahal",
"str_open_time": "10:00:00",
"str_close_tie": "23:00:00",
"str_open_date": "2017-01-29",
"str_close_date": "2018-01-28",
"str_logo_path": "",
"str_logo_file_name": "Moti mahal.png",
"status": "Y",
"str_cat": "1",
"company_id": "0",
"str_lat": "0",
"str_lon": "0",
"create_at": "2017-02-11 19:45:28",
"create_by": "0",
"str_zone": "1",
"str_floor": "0",
"str_availability": "1",
"str_multiple_cat": "1"
},
{
"str_id": "2",
"str_number": "0",
"tid": "",
"str_name": "Ever Green",
"str_des": "",
"str_phone": "9953487923",
"str_add": "",
"str_parking": "Green Floor",
"str_short_dis": "Snakes",
"str_open_time": "10:00:00",
"str_close_tie": "22:00:00",
"str_open_date": "2017-02-05",
"str_close_date": "2017-12-31",
"str_logo_path": "",
"str_logo_file_name": "Ever Green.jpg",
"status": "N",
"str_cat": "1",
"company_id": "0",
"str_lat": "0",
"str_lon": "0",
"create_at": "2018-01-15 22:20:11",
"create_by": "0",
"str_zone": "1",
"str_floor": "0",
"str_availability": "1",
"str_multiple_cat": "1"
}
]
}
the same json file is working fine in android but not working in iOS. I am stuck here from a very long time.
All the other questions on StackOverflow is stating that my JSON file is not valid but it's working elsewhere.
Note. Feel free to edit my question if there any issues.
I have gone through all the similar questions but none of them is working in my scenario.
solved the issue, just needed to add POST request to the URL
foodUrl.httpMethod = "POST"

Swift Create Json for API REST

I need create a json for send from a API REST:
{
"ownId": "seu_identificador_proprio",
"amount": {
"currency": "BRL",
"subtotals": {
"shipping": 1000
}
},
"items": [
{
"product": "Descrição do pedido",
"quantity": 1,
"detail": "Mais info...",
"price": 1000
}
],
"customer": {
"ownId": "seu_identificador_proprio_de_cliente",
"fullname": "Jose Silva",
"email": "nome#email.com",
"birthDate": "1988-12-30",
"taxDocument": {
"type": "CPF",
"number": "22222222222"
},
"phone": {
"countryCode": "55",
"areaCode": "11",
"number": "66778899"
},
"shippingAddress": {
"street": "Avenida Faria Lima",
"streetNumber": 2927,
"complement": 8,
"district": "Itaim",
"city": "Sao Paulo",
"state": "SP",
"country": "BRA",
"zipCode": "01234000"
}
}
}
I am confused with the creation..
I try begin with [NSObject:AnyObject]
var d1 : [NSObject:AnyObject] = ["ownId":"seu_identificador_proprio", "customer":""]
let dd1 = ["currency":"BRL"]
let dd2 = ["shipping":"1000"]
let arr = [d1]
let d = try! NSJSONSerialization.dataWithJSONObject(arr, options: NSJSONWritingOptions.PrettyPrinted)
let s = NSString(data: d, encoding: NSUTF8StringEncoding)! as String
print(s)
But I need help!
I have updated your code and added some hints, how can you build the above listed structure. Happy coding!
// Do not use NSObject as key's type
// Keys in a dictionary are usually Strig in every language
var d1: [String: AnyObject] = ["ownId":"seu_identificador_proprio", "customer":""]
// Define the type of your dictionaries, if you dont, in this case it will create a [String:String] dictionary, but you need to insert an array into it
// Make it a var, so you can mutate the container
var dd1: [String: AnyObject] = ["currency":"BRL"]
// Here the type is undefined. Try inserting anything else than String, and see the results
let dd2 = ["shipping":"1000"]
dd1["subtotals"] = dd2
d1["amount"] = dd1
// Build all your dictionaries like i did above, and at the end add all of them into arr
let arr = [d1]
// Do not force try any throwing function in swift - if there is an error, your application will crash
// Use proper error handling - https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html
do {
let d = try NSJSONSerialization.dataWithJSONObject(arr, options: NSJSONWritingOptions.PrettyPrinted)
let s = NSString(data: d, encoding: NSUTF8StringEncoding)! as String
print(s)
} catch {
// Do your error handling here
}

Resources