iOS parse string with multiple JSON objects? - ios

I'm having some troubles when my app receives multiple JSON objects at the same time. I'm using a TCP socket that is open to my server which sends me messages. The reason i seem to recieve multiple messages is probably due to network lag.
This is what a server message can look like (i then put this into a NSString and try to parse the JSON):
{
"id": "156806",
"type": "message",
"userCity": "",
"userCountry": "",
"os": "",
"browser": "",
"trafficType": "",
"seKeyword": "",
"seType": "",
"currentPage": "",
"userId": "1",
"agentId": "352",
"customField1": "",
"visitorNick": "Visitor 147220060",
"msg": "asd",
"time": "16:05",
"channel": "V147220060",
"visits": "254"
} {
"type": "previewStopped",
"msg": "",
"visitorNick": "Mackan",
"customField1": "",
"visitorNick": "Visitor V147220060",
"time": "16:05",
"channel": "V147220060"
} {
"id": "156807",
"type": "message",
"userCity": "",
"userCountry": "",
"os": "",
"browser": "",
"trafficType": "",
"seKeyword": "",
"seType": "",
"currentPage": "",
"userId": "1",
"agentId": "352",
"customField1": "",
"visitorNick": "Visitor 147220060",
"msg": "as",
"time": "16:05",
"channel": "V147220060",
"visits": "254"
} {
"id": "156808",
"type": "message",
"userCity": "",
"userCountry": "",
"os": "",
"browser": "",
"trafficType": "",
"seKeyword": "",
"seType": "",
"currentPage": "",
"userId": "1",
"agentId": "352",
"customField1": "",
"visitorNick": "Visitor 147220060",
"msg": "da",
"time": "16:05",
"channel": "V147220060",
"visits": "254"
}
And here is how i currently parse the NSString, note that the above JSON is outputData in the code below:
// Parse the message from the server
NSError* error;
NSDictionary *JSON =
[NSJSONSerialization JSONObjectWithData: [outputData dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
NSString* type = [JSON objectForKey:#"type"];
if(error) {
NSLog(#"PARSE ERROR ------------->>>>> : %#\n", error);
}
NSLog(#"SERVER TYPE --> %#\n", type);
if([type isEqualToString:#"message"]) {
[self messageReceived:outputData];
}
The above works perfectly when i only recieve one JSON in outputData but when multiple JSONs are recieved it trows an error:
PARSE ERROR ------------->>>>> : Error Domain=NSCocoaErrorDomain
Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)"
(Garbage at end.) UserInfo=0x14e9acb0 {NSDebugDescription=Garbage at
end.}
Any ideas how to handle this?

Hmm...you could wrap it yourself. Take the data you get and prepend "{ "dataarray": [" to the beginning, and "] }" to the end. This will produce an array, the elements of which will be your individual JSON entities.

Try this:
NSData *jsonData = [outputData dataUsingEncoding:NSUTF8StringEncoding];
NSArray *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&e];
NSDictionary *JSON = [dict objectAtIndex:0];
NSString* type = [JSON objectForKey:#"type"];
EDIT:
An example of JSON, because your "" can cause problems:
{
aula = "AULA M04";
cuatrimestre = "Primer quadrimestre";
dia = Dimecres;
edificio = "AULARI V";
fin = "18:00";
inicio = "15:00";
}
Hope it helps!

It's erroring out because you don't have valid JSON in your string. You'll need to do something like the following to get it into the correct format:
NSString *formattedString = [NSString stringWithFormat:#"[%#]", [outputData stringByReplacingOccurrencesOfString:#"} {" withString:#"},{"]];
NSError *error = nil;
NSArray *JSON = [NSJSONSerialization JSONObjectWithData:[formattedString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];
That is assuming outputData is an NSString.

If your data stream contains multiple JSONs in sequence, it strictly isn't JSON anymore. Rather, it is a custom protocol which embeds JSON.
You need to first define your custom protocol. It can be defined as an arbitrary number of JSONs in sequence - if this fits your needs. NSJSONSerialization isn't capable to parse your custom protocol, though.
You could define your protocol differently, for example: your data is a contiguous stream of messages, where a message is a "blob" prepended by value representing the length in bytes, e.g.:
message := message_size CRLF blob
message_size := digits
data := message*
That is, your data may look as follows:
2\n\r[]4\n\r5["a"]
This is of course a pretty naive protocol, but it should be sufficient to demonstrate the basic idea.
Your blob could then be JSON UTF-8.
This "protocol" can be easily parsed with a custom parser, where the "blob" (a single JSON) will be passed through a JSON parser, possibly wrapped into a NSData object.

Related

Authorize.net payment gateway Charge a Credit Card API for iOS swift

hello everyone as i am using payment gateway charge credit api but i am getting error while passing json object to api.and here my original JSON object which pass to charge credit api.
{
"createTransactionRequest": {
"merchantAuthentication": {
"name": "XXXXXX",
"transactionKey": "XXXXXXXX"
},
"refId": "123456",
"transactionRequest": {
"transactionType": "authCaptureTransaction",
"amount": "5",
"payment": {
"creditCard": {
"cardNumber": "5424000000000015",
"expirationDate": "2020-12",
"cardCode": "999"
}
}
}
}
}
this is original json request
but in iOS while making JSON we get below JSON object and sequence of JSON object are change that's why we getting error from api.
{
"createTransactionRequest": {
"merchantAuthentication": {
"name": "XXXXXX",
"transactionKey": "XXXXXXX"
},
"refId": "123456",
"transactionRequest": {
"amount": "5",
"payment": {
"creditCard": {
"cardCode": "999",
"cardNumber": "5424000000000015",
"expirationDate": "2020-12"
}
},
"transactionType": "authCaptureTransaction"
}
}
}
after passing this JSON object to API, we will get bellow error
{
"messages": {
"resultCode": "Error",
"message": [
{
"code": "E00003",
"text": "The element 'transactionRequest' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has invalid child element 'amount' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of possible elements expected: 'transactionType' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'."
}
]
}
}
here is my code for creating JSON object in app
var dict = Dictionary<String, Any>()
dict=[
"merchantAuthentication": [
"name": "xxxxxxx",
"transactionKey": "xxxxxxx"
],
"refId": "5656",
"transactionRequest": [
"transactionType": "authCaptureTransaction",
"amount": "55",
"payment": [
"creditCard": [
"cardNumber": "4111111111111111",
"expirationDate": "2020-12",
"cardCode": "999"
]
]
]
]
after print this JSON sequence are changed
Have you read the documentation? It's very clear from the linked page that what you're running into is a side effect of their translation of JSON elements to XML elements in the backend, specifically around the ordering of parameters in your JSON request:
A Note Regarding JSON Support
The Authorize.Net API, which is not
based on REST, offers JSON support through a translation of JSON
elements to XML elements. While JSON does not typically require a set
order to the elements in an object, XML requires strict ordering.
Developers using the Authorize.Net API should force the ordering of
elements to match this API Reference.
Their examples below this block also show that their transactionType parameters appear as the first attribute in the transactionRequest object. Tl;dr - move your transactionType parameter up in your transactionRequest object:
{
"createTransactionRequest": {
"merchantAuthentication": {
"name": "XXXXXX",
"transactionKey": "XXXXXXX"
},
"refId": "123456",
"transactionRequest": {
"transactionType": "authCaptureTransaction",
"amount": "5",
"payment": {
"creditCard": {
"cardCode": "999",
"cardNumber": "5424000000000015",
"expirationDate": "2020-12"
}
}
}
}
}
please try with following code.
let merchantSub = ["name": "XXXXXX",
"transactionKey": "XXXXXXX"]
let childCreditCard = ["cardCode": "999",
"cardNumber": "5424000000000015",
"expirationDate": "2020-12"]
let creditCard = ["creditCard":childCreditCard]
let transactionRequest = ["amount": "",
"payment":creditCard,
"transactionType":""] as [String : Any]
let merchantAuthentication = ["merchantAuthentication" :merchantSub,
"refId" : "123456",
"transactionRequest":transactionRequest] as [String : Any]
let param = ["createTransactionRequest" : merchantAuthentication]
if let data = try? JSONSerialization.data(withJSONObject: param, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str)
}
However I recommend to use class but for initial level do like this.

Parse JSON with Swift JSON

How to get Value Radio Name With Swift JSON
I wrote like this
let response = JSON["topradio"]["Data"]
before this i created model for values but am not able to pic values like radio_name
{
"topradio": {
"result": "success",
"Data": [
[
{
"radio_name": "Kantipur",
"rimage": "radio/1422960479145155755920731096211441695162.jpeg",
"status": "1",
"user_faverate": "false",
"popular_radio": "0",
"radio_id": "4"
}
]
[
{
"radio_name": "Kantipur",
"rimage": "radio/1422960479145155755920731096211441695162.jpeg",
"status": "1",
"user_faverate": "false",
"popular_radio": "0",
"radio_id": "4"
}
]
]
}
Thanks in Advance
You can iterate through your nested data Array this way.
let dataArray = JSON["topradio"]["Data"].array
for item in dataArray {
let itemArray = item.array
for subItem in itemArray {
if let name = subItem["radio_name"].string {
print(name)
}
}
}

Swift 3 looping JSON data

I'm attempting to loop through a JSON array sending data to a struct.
Here's my code that uses SwiftyJSON to return a JSON object:
performAPICall() {
json in
if(json != nil){
print("Here is the JSON:")
print(json["content"]["clients"])
let clients = json["content"]["clients"]
for client in clients {
var thisClient = Client()
thisClient.id = client["id"].string
thisClient.desc = client["desc"].string
thisClient.name = client["name"].string
self.clientArray.append(thisClient)
}
self.tableView.reloadData()
} else {
print("Something went very wrong..,")
}
}
I'm not quite sure why I'm getting "has no subscript" errors on the three strings.
Any help appreciated, thanks.
EDIT: Here's a sample of the JSON
{
"content": {
"clients": [{
"group": "client",
"id": "group_8oefXvIRV4",
"name": "John Doe",
"desc": "John's group."
}, {
"group": "client",
"id": "group_hVqIc1eEsZ",
"name": "Demo Client One",
"desc": "Demo Client One's description! "
}, {
"group": "client",
"id": "group_Yb0vvlscci",
"name": "Demo Client Two",
"desc": "This is Demo Client Two's group"
}]
}
}
You should use array method. Thus, your line
let clients = json["content"]["clients"]
should use array (and unwrap it safely):
guard let clients = json["content"]["clients"].array else {
print("didn't find content/clients")
return
}
// proceed with `for` loop here

How to get NSArray from json

I have a JSON like this
{
accountList: [
{
acctId: "",
acctType: ""
},
{
acctId: "",
acctType: ""
}
],
tokenBack: "",
userId: "",
verificationCode: ""
}
and i want accountList array from that JSON as an array. Any one have solution?
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:_responseData options:NSJSONReadingMutableContainers error:nil];
NSArray *accountList = result[#"accountList"];

How to pass an array in an url query parameter using nsurl in objective-c?

The API need to pass an array in an url query parameter, how to acheive this in iOS?
I only know how to pass a single vaue, like the API below : ?title=Design Milk&id=feed/http://feeds.feedburner.com/design-milk
API sample:
"title": "Design Milk",
"id": "feed/http://feeds.feedburner.com/design-milk",
"categories": [
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"label": "design"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
"label": "weekly"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
"label": "must reads"
}
]
Create a collection and then use NSJSONSerialization to create JSON data representation. Use the resulting data as the POST data.
NSDictionary *parameters = #{
#"title": #"Design Milk",
#"id": #"feed/http://feeds.feedburner.com/design-milk",
#"categories": #[
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
#"label": #"design"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
#"label": #"weekly"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
#"label": #"must reads"
}
]
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictData options:0 error:&error];

Resources