Is there a way to construct an object automatically from an NSDictionary? - iphone

I'm building an iPhone app that communicates with an external server via JSON. The JSON library I'm using parses the response string from the server into a dictionary. Currently I've got a method that I've written that just uses hardcoded strings as keys for the dictionary in a constructor I've written called initWithDictionary:(NSDictionary *)dic (e.g. self.name = [dic valueForKey:#"name"];. Is there some smart idiomatic Objective-C way to do this?

Just call [someObject setValuesForKeysWithDictionary:dictFromJSON] to set an object's properties from a dictionary.

Related

How to use my Class with PList in objective-c?

I have a Class for handling my data in my project, and now I need to store the data.
I'd like to use a Plist but I'm a bit unsure of how to start.
My class is pretty simple - 6 pieces of data, flat (no hierarchy).
I want my app to start with no data, so can I assume that I should create the PList programmatically once the User creates their first piece of data? (That is, don't create a .plist file in 'Supporting Files' prior to distribution?)
Then, when the app starts the next time, read the data and create an NSMUtableArray array of Class instances?
To create a property list, all you need to do is use appropriate types (i.e. those that support the property list format: NSData, NSString, NSDictionary, NSNumber, NSDate, NSArray), store them in a single container, and tell the containing object to write itself to a file. To read the data, you can initialize that same type using a path. For example:
// writing some data to a property list
NSString *somePath = ... // replace ... with the path where you want to store the plist file
NSMutableDictionary myDict = [NSMutableDictionary dictionary];
[myDict setObject:#"Caleb" forKey:#"name"];
[myDict setObject:[NSNumber numberWithInt:240] forKey:#"cholesterolOrIQ"];
[myDict writeToFile:somePath atomically:YES];
// reading the file again
NSDictionary *readDict = [NSDictionary dictionaryWithContentsOfFile:somePath];
The simplest way is to simple save an NSArray or NSDictionary to disk. Caleb's answer goes into detail there so I won't repeat it, other than to say you might have to convert a non-compatible object like NSColor to an property list object like NSData. It's up to you to do this each time you save or load your data.
NSKeyedArchiver and NSKeyedUnarchiver give you a little more control over the process, but work pretty much the same way. You provide (or get back) a plist compatible root object (usually an NSDictionary) that contains your data. I recommend creating a dictionary that includes your data structure as well as an arbitrary number (your app's build number is a good choice) to use as a version indicator. This way if you ever update your data model you can easily determine if you need to do anything to convert it to the new version.
If you're putting your own objects into the data file, look into NSCoding. The protocol gives you two methods using NSKeyedArchiver and NSKeyedUnarchiver to save and restore your data. This is by far the most straightforward approach if your data model consists of anything more than a few simple strings and numbers, since you're dealing with your own native objects. In your case, you would have your data class implement NSCoding and use the NSKeyedArchiver and NSKeyedUnarchiver methods to encode your six instance variables. When it's time to save or load, pack the instance of your class into an NSDictionary (along with a versioning number as I mentioned above) and call NSKeyedArchiver's archiveRootObject:toFile:. Your save an load methods deal only with your own data object, which makes things easy for you. The common pitfall to watch out for here is if your custom data object contains other custom object. This is fine, but you have to make sure every object that's going to be saved has its own NSCoding implementation.
Two things you can do:
Use NSUserDefaults:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
The objectForKey method is the one you want to use to store your class. But, as pointed out in the comments, this shouldn't really be used for storing lots of user data; it's best for saving preferences.
For storing more data, you might want to look at Core Data. It's more complex, but should be better suited to your needs. Here's a tutorial on it:
http://mobile.tutsplus.com/tutorials/iphone/iphone-core-data/
Neither of these seems best for your simple application, but I leave this answer up since it gives alternatives for saving data to the iPhone.

Remove escaping of quotes with Newtonsoft.Json

I have a WCF service. URL is: http://iphone.clickcelltest.com/EduLink.svc/GetLevel
Methods have following attribute:
[WebGet(ResponseFormat=WebMessageFormat.Json)]
I get Data from Database and then in Collection/List of classes.
I use Newtonsoft.Json DLL to convert the collection to json string. It does it very well but i need to send this to iPhone.
But, i get unnecessary escaping of quotes. I understand the reason why it is happening.
But, is there a way to avoid it
So, how can i change the current result:
"{\"Object\":[{\"LevelID\":4,\"LevelName\":\"Level A\"}]}"
To
{"Object":[{"LevelID":4,"LevelName":"Level A"}]}
Let me know if more clarity is required.
Thanks much in advance.
That looks like the result of returning a manually JSON-serialized string, which WCF is then serializing again. Rather than returning a string that you've built with Json.NET, make your service's return value match the type of data you're returning and return that data directly.
If you specifically need to use Json.NET for some reason, using an HttpHandler instead of WCF would allow you to respond at that lower level without WCF interfering.
Use stringByReplacingOccurencesOfString method in NSString class
NSString * jsonString = #"{\"Object\":[{\"LevelID\":4,\"LevelName\":\"Level A\"}]}";
NSString * filteredString = [jsonString stringByReplacingOccurrencesOfString:#"\\" withString:#""];
NSLog (#"%#",filteredString);

Extracting the copyable identity of the non-copyable object

I need to use non-copyable objects as keys in the NSMutableDictionary which, by default, is not allowed. I understand the reasons for this not being allowed (retaining the key object, unlike the value object, is undesirable), but it seems like in my particular situation there could be a way around this.
The thing is that I'm only need to query the dictionary using the key's address, i.e. having the lookup predicate
if (providedKey == storedKey)
instead of
if ([providedKey isEqual:storedKey])
would be perfectly sufficient.
Is there a way of extracting the object's reference address (or other form of identity) as a copyable comparable object which I could use as a dictionary key instead of the object itself?
It seems that +[NSValue valueWithPointer:] might be what you want. It stores the pointer itself in an object that conforms to NSCopying, so that you can use it as a dictionary key. Retrieve the pointer using pointerValue.
You could use [NSString stringWithFormat:#"%p", someObject] as your key.
This will create a string with the object's address as a hex value.
You could use an nsnumber that represents the hash of the object.
you can drop down to the CoreFoundation APIs and define you own callbacks (among other things).
NSMutableDictionary is a CFMutableDictionary.
specifically, you want to create a CFMutableDictionary, and define your own CFDictionaryKeyCallBacks.

Iphone JSON-Framework

is posible using JSON-Framework for Iphone to know if a tag exists inside the JSON like in JAVA with the function hasTag(String)?
If by tag you mean name/key and you’re using SBJSON, use -objectForKey: and test if the return value is nil. For instance, if person is an NSDictionary instance returned by the JSON parser and it can optionally contain a nickname,
if ([person objectForKey:#"nickname"] != nil)
{
// `nickname' is available; do something with it
}
The way I think to do it is to convert your JSON Object to an NSDictionary and after that use the method -(NSArray *)allKeys, or -(NSArray *)allValues depending what you want.
It returns an array with all the keys (or values) inside the object. You can then compare the keys with the one you want to find.
Hope it helps you.

OSX: How to store objects in plist file in an OO way

I feel a little dumbfounded. I know how to store any kind of "plist supporting" data in a preferences file, such as NSArray, NSDictionary, NSString and their CF counterparts. No problem there.
Now I like to store the values of my custom object this way. I had thought that if I implement some kind of serialization/archiving protocol, I could get NSUserDefaults to understand my class just like it understand NSDictionary.
E.g, implementing the NSCoding protocol should give the NSUserDefaults code all that it needs: I give it the key names along with the values as plist compatible types (NSString, mostly in my case). But my encoder doesn't even get invoked. :(
Then I thought that there must be at least some function that generates a NSDictionary from the NSCoding protocol, so that I can then send this dict to store in the prefs. Ideally, there'd by something like the NSKeyedArchiver that I pass any NSCoding compatible object and it gives me a NSDictionary, and vice versa. But that doesn't appeat to exist in Apple's framework.
Do I have to write that really myself? I'd expect this would be a quite common need.
Note: I realize that NSKeyedArchiver generates a binary plist, which I could write as a plist file. But that's not what I want. I want to add the contents of this object to my app's prefs plist file, i.e. I want to store both my object and other prefs data in the plist file. That's what doesn't seem to be possible with the given functions.
I'm currently just adding objects to an NSDictionary then calling NSDictionary's "writeToFile:atomically:" method. I'm mostly adding strings, and an image as NSData, but I believe anything I add to the NSDictionary that implements the NSCoding protocol should get written to the file.
Then later when I call NSDictionary's initWithContentsOfFile everything gets put back in the dictionary as it had been. Would this work for you - letting the dictionary take care of the serialization stuff?