How to prevent order changing in NSDictionary in ios - ios

Hi In my application I have a login screen where I have to post credentials to C# server.The order which I used is as such below
username
password
domainname
Code:
NSDictionary*disPost=[[NSDictionary alloc]initWithObjectsAndKeys:#"naresh",#"UserName",#"n123",#"Password",#"naresh-in",#"DomainName",nil];
I can able to post the data to server successfully but the credentials order is changing like below.
Password
UserName
DomainName
Due to this reason I am getting an exceptional error from server. Please help me to resolve this issue as soon as possible.

NSDictionary has key-value pairs, it is not ordered. You need an array to keep the order of the elements. You could use 2 arrays (1 for keys the other for values) or use an array for keys (to know the order) and a dictionary for the key-value pairs.

NSDictionary is not an ordered container. If you really want an ordered dictionary then use OrderedDictionay from,
http://www.cocoawithlove.com/2008/12/ordereddictionary-subclassing-cocoa.html

Your question makes me think that its not NSDictionary that you want to use, because with dictionaries you really shouldn't care about the order.
And I think the glitch in your code is probably with the part that sends to the server, try sending them separately, or use another datatype than NSDictionary.
good luck!

Related

NSDictionary inconsistent behaviour as params

I've found that when using NSDictionary to create the params for an AFNetworking POST request the behaviour is inconsistent. I have multiple POSTs where the params arrive at the server in the same order I created them in the NSDictionary and now creating a new request they are arriving at the server in a different order.
This is how I send them:
NSDictionary *params = #{#"username": #"testuser", #"count": #"6"};
But this is how it arrives on the server:
{"count":"6","username":"testuser"}
Its important for me that it arrive at the server exactly the same as it leaves my app as I hash together values for integrity and can't verify if it arrives in a different order to how it leaves.
I know NSDictionary is by nature not expected to keep the order, is there anyway using NSDictionary or another way I can guarantee the order?
Thanks in advance
You'd have to use an ordered dictionary class. Unfortunately, there's not one in the Foundation framework, but it's fairly easy to create (or even download) your own. This article describes how to create an ordered dictionary class in Objective-C, and includes source code.

Storing a set of parameters in a dictionary

I have a networking method that provides a friendly interface to my API. Something like:
getWeatherForCities:(NSArray *)cityCodes
startDate:(NSDate *)startDate
endDate:(NSDate *)endDate
useCelcius:(BOOL)useCelcius
maxResults:(NSNumber *)maxResults
This is called multiple times in my app, sometimes concurrently with different parameters. There is also a completion and failure block but they aren't needed here.
I would like to add an option that tells the method only to execute the completion block if the data is different to the last time it was requested with the same parameters. This way some consumers can say that they want to know everything, and others can ask only for data if it is new.
It seems like I need some way to store a representation of all the parameters, alongside the last received response for those parameters. I would love to do this in an NSDictionary, but am open to other ideas. Is there some way to convert the parameters into a unique key? Or some better solution?
I am currently using the [dictionary description] as the key.

How to safely treat data from JSON when the expected type may differ?

As of iOS 5 and OSX 10.7 and higher it is really easy to parse JSON with NSJSONSerialization, which will return either an NSDictionary or NSArray (or mutable variants, if specified) when parsing JSON. Values are parsed as common Cocoa types such as NSString and NSNumber however I would be interested to know how careful I need to be when taking the data from the NSDictionary or NSArray and parsing it into data objects in my app. My key concerns are whether the key's value a) is not nil and b) isn't of an unexpected type.
For example, assume I had the following JSON object:
{
"version":1,
"title":"Some interesting title",
"info":"Some detail here"
}
Currently, this would be parsed as an NSDictionary:
#{
#"version": #1,
#"title":#"Some interesting title",
#"info": #"Some detail here"
}
My problem is how careful I should be when checking the data types of what I'm getting back. In theory, if I'm using a good API I should always get a numeric value for the version key, but what if for some reason it is changed server side to the following:
{ "version:"1", ... }
Or even worse:
{ "version:"one", ... }
If I attempt the following code, I will get hit an exception and my app would crash:
NSNumber * myNumber = dictionary[#"version"];
if ([myNumber isEqualToNumber:#1])
{
...
}
The code wouldn't execute because a) dictionary[#"version"] would be an NSString and b) isEqualToNumber: is only available on NSNumber (unrecognized selector exception, app would crash).
Equally, problems could arise if the JSON for "info" was changed to the following:
{
"info":{
"code":200,
"message":"Some detail here"
}
}
If my app expects an NSString for the key info it will again crash, because an NSDictionary will have been found instead.
On the large part, most JSON from an API or file should be sound and supported by the current version of the app and one would hope that all JSON is versioned and correctly encoded server side. In some cases, if the JSON has been corrupted or modified, the app could crash, which I want to avoid.
Potential solutions:
Check every single key/value pair for isKindOfClass: or respondsToSelector: and only continue if true
Check the key exists and produce an error if nil
Wrap up everything in a try/catch block, however I would rather what can be used is used and an error is produced if something is wrong with the data. This could end up with a lot of #try/#catch statements inside one another
Each of these solutions is rather bulky and adds a lot to my code which I would prefer to avoid, if possible (and when working with 'good' JSON it is perfectly possible). If there is an alternative solution that will handle the process of parsing JSON, checking keys' type and values before putting it in a custom object I would love to know.
You should generally be running against a stable API. The kind of changes you're worried about should be accompanied by a version number change in any reasonable system which would insulate your app from the change until an appropriate upgrade time. So, you should generally know the data type to expect.
In some cases the API will specify that a dictionary or an array may be received depending on the multiplicity, something like that. In this case you should check the class and act accordingly.
You should definitely check for nil and NSNull and handle those gracefully.
Corrupted JSON should be handled by the parser and an appropriate error returned to you.
Also, you could use a framework like RestKit to do the mapping to your custom objects for you. It does a lot of data type checking as standard and removes basically all of your mapping code into a simple configuration. It also handles all of the network comms (via AFNetworking).
You need to make sure your code is safe against attacks from hackers. When you request JSON from a server, you must expect that the data doesn't come from your server but from somewhere else, and that someone else might have designed the data returned to cause maximum damage. Now just crashing if you receive a string instead of a number is quite secure.
You must expect that your request to the server is instead fulfilled by some brain damaged hardware that tries to be "helpful" for example when an internet connection fails. Instead of JSON you might receive a "helpful" website that is supposed to tell a user how to reset their router. A user trying to use someone's free WiFi may have connections return weird result. That's usually no problem with JSON because the parsing will fail (so failed parsing is something you should expect and handle), more of a problem if you expect html.
You must expect that a public API that you are using has bugs or unexpected behaviour and you should behave well when that happens. Add debugging code that will at least log anything unexpected while you are developing. Write your code so that it works with any behaviour that the API shows.
If you are using your own API, you should also log anything unexpected, and then tell the server people if they do anything they shouldn't.

How to retain order of JSON data retrieved with AFNetworking?

I am using AFNetworking to retrieve JSON data from a web service. Part of the response string I get is:
{"DATA":{"LEASE TYPE":"3 Yrs + 0 renew of 0 Yrs","LANDLORD":"","TENANT":"test comp"...
and so on. The order of the key values in the "DATA" dictionary ("LEASE TYPE","LANDLORD","TENANT"...) is important for presentation purposes. However, when AFNetworking calls NSJSONSerialization's:
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
method, the returned dictionary has the keys in a different order.
I notice that the AFJSONRequestOperation object has the server's response stored as an NSString, with everything in the correct order. However I'm not keen on parsing the JSON by hand if I can avoid it.
Can anyone suggest a way that will let me get at / keep the keys in their original order?
Thanks.
If the order is important use an array not a dictionary, dictionaries are be by their nature unordered. Or add an array of dictionary keys in the order desired.
If you have no control over the response that is sent you will have to parse the JSON yourself at least for the ordering.
When you'r creating an NSDictionary, the order will not be the same. I often recognized that dictionaries get ordered by key-name alphabetically.
But when using dictionaries the order doesn't really matter. And they shouldn't!
As the previous answers mentions dictionaries are by nature without order, but you can find here a nice class of OrderedDictionary:
http://www.cocoawithlove.com/2008/12/ordereddictionary-subclassing-cocoa.html
http://projectswithlove.com/projects/OrderedDictionary.zip

Error on saving object in AFIncrementalStore. ResponseObject is an NSArray instead if NSDictionary despite valid JSON resposne

All,
I am trying to solve an issue now for the last two days and seem incapable. Apologies in advance if asking for the obvious.
In a very simple data model I try to insert a new object user. (attributes: name, password and id which are respectively a NSString, a NSString and a NSNumber). The new object gets successfully created
in the API and the external MySQL server. However, in the completion block of the HTTPrequest when
(I think) the backing store is populated it tries to create the resource identifier.
This is were the app crashes in this method when it is trying to get allKeys from the representation dictionary:
(NSString *)resourceIdentifierForRepresentation:(NSDictionary *)representation ofEntity:(NSEntityDescription *)entity fromResponse:(NSHTTPURLResponse *)response
The JSON response getting back from the server is as follows:
[{"id":20,"name":"john doe","password":"secret"}]
Anyone a clue? Would be very grateful if I could solve the issue this year!!!
Side notes: Matt great job!
Side question: How will AFIS deal with local storage, local changes and synching with the server when a connection is back?
All,
Thanks in advance and enjoy 2013!!!
[Update]
The issue is that I get an NSArray back instead of a NSDictionary. I can simply fix it by changing the code in AFIS savecontext to pass the responseObject[0] however I prefer not to change the AFIS code and I still find it odd that I dont get an NSDictionary back when I have a valid JSON response
You can override the method that AFIS uses to get the resulting object from the json data.
- (id)representationOrArrayOfRepresentationsOfEntity:(NSEntityDescription*)entity
fromResponseObject:(id)responseObject
The response object should be your array with dictionary at index 0.

Resources