NSDictionary or custom NSObject for JSON parsing - objective-c

I've seen a lot of people use NSDictionary for JSON parsing:
//ViewController.m
NSString* forename = [jsonDict valueForKey:#"forename"];
NSString* surname = [jsonDict valueForKey:#"surname"];
But I've also people creating custom NSObjects from a NSDictionary.
//JSONObject.h
#interface JSONObject : NSObject
#property (nonatomic) NSString* forename;
#property (nonatomic) NSString* surname;
#end
//JSONObject.m
#implementation JSONObect
#synthesize forename = _forename;
#synthesize surname = _surname;
#end
//ViewController.m
JSONObject* jsonObject = [[JSONObject alloc] init];
[jsonObject setForename:[jsonDict valueForKey:#"forename"]];
[jsonObject setSurname:[jsonDict valueForKey:#"surname"]];
And then store these in a NSMutableArray:
NSMutableArray* jsonObjectsArray = [NSMutableArray arrayWithCapacity:20];
[jsonObjectsArray addObject:jsonObject];
Which can be accessed later if needed.
In my case, I have a UITableView that gets it's data from JSON. The data is used at least once but most likely will be used more (eg. on device rotation). The JSON data shouldn't be permanently stored to file as it is updated regularly and is downloaded every time the app launches.
Should I use a custom NSObject or a NSDictionary in my scenario?

One argument for using a custom Object is that it is a few short steps away from using a NSManagedObject, which would let you leverage Core Data to manage your object graph.

The argument for using the NSDictionary is that it's simpler and easier to understand, and you define fewer "minor" classes (and associated h/m files), so less to manage in a project. Also a lot easier to edit/extend in a project "in flux".

Related

Search array of NSObjects containing Arrays

I have an Array full of PhRecords. For simplicity sake, let us consider the structure of object is as follows:
#interface PhRecord : NSObject
#property (nonatomic, strong) NSArray *PhName; //Person's name
#property (nonatomic, strong) NSArray *PhNumbers; //Person will have 2/3 contact numbers
#property (nonatomic, strong) NSArray *PhTypes; //The types of the contact numbers
#end
There is a property in my class which goes through the phone book and collects the names and phone numbers in an array in the format specified above. Let's say the array is the following
#property (nonatomic, strong) NSArray *allContacts;
Also, I have method to get all contacts as PhRecords with the following method
- (NSArray *)getAllContacts;
I have a method where if I give the contact number, it will find the name and type of the contact.
//Assume that both string1 and string2 don't have (,),*,#,+ and "<white space>"
- (void)findContactByPhoneNumber:(NSString *)phNum {
NSString *string1 = phNum;
NSArray *contacts = [self getAllContacts];
for(SDPhoneRecord *record in contacts) {
for(int j=0;j<record.PhNumbers.count;j++) {
NSString *string2 = [[record.PhNumbers objectAtIndex:j];
if([string2 rangeOfString:string1].location!=NSNotFound) {
NSLog(#"Name:%#,Type:%#",record.PhName,[record.PhTypes objectAtIndex:j];
}
}
}
}
As you can see, this search has time complexity of O(n^2). Is it possible to do a O(1) lookup? If I have to use predicates, how can I use them with this kind of requirement where a "range" of string has to be compared with the string passed argument?
To improve the "big O" you need to eliminate loops, not simply hide them. This generally implies using some sort of "look at" mechanism, vs a "look up" mechanism -- a mechanism that uses, eg, a hash table to locate item. The main such mechanism in Objective-C is the NS(Mutable)Dictionary, which internally contains a hash table.
In some cases it's possible to employ properties of the data to improve search efficiency, but absent that the hash table is usually the best (and most general) approach.
Use the NSArray objectsPassingTest where the test is if the phone number attribute is equal to the provided string

Subclassing iOS Model Objects - Appropriate Design Pattern

I fear this is a rather simple question, but after much googling I think I have overshot my intended result. I believe my question to be related to a design pattern, but alas I could be wrong.
My application calls an RESTful API and gets back what amounts to a list of model objects represented by an NSDictionary. Each of which I will call NNEntity. There are (conceptually) multiple different subtypes of NNEntity. All subtypes of NNEntity share the property of entityID, but each have their own unique properties as well. All instances of NNEntity have a method called readFromDict:(NSDictionary *)d that populates their respective properties. This method is enforced by a protocol that all NNEntity subtypes conform to. It looks like this:
//NNEntity.h
#interface NNEntity : NSObject <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *entityID;
#end
//NNEntity.m
#implementation NNEntity
- (void)readFromDict:(NSDictionary *)d {
//set common properties from values in d
self.entityID = [d objectForKey:#"ID"];
}
#end
//NNSubEntity1.h
#interface NNSubEntity1 : NSEntity <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *favoriteColor;
#end
//NNSubEntity1.m
#implementation NNSubEntity1
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.favoriteColor = [d objectForKey:#"colorPreference]:
}
#end
//NNSubEntity2.h
#interface NNSubEntity2 : NSEntity <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *middleName;
#end
//NNSubEntity2.m
#implementation NNSubEntity2
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.middleName = [d objectForKey:#"middleName]:
}
#end
I have read various pieces on the use of a Factory or Builder Desing pattern for similar use cases but I am curious if that is necessary in this rather simple case. For example, does my current code end up creating both and instance of NNEntity and NNSubEntity2 if I were to call something like this:
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];
I assume not, but would newEntity have both the common property of entityID as well as the unique property of middleName set correctly? Also, much appreciated if you have thoughts on a better or more efficient design approach.
This looks like exactly how you should be doing it. You have a base class which read in the common attributes, and subclasses which read in their specific attributes.
For example, does my current code end up creating both and instance of NNEntity and NNSubEntity2? NNEntity *newEntity = [[NNSubEntity2 alloc] init];
Nope. When you run this, you instantiate NNSubEntity2 and store the result in a variable typed by it's superclass, which is totally valid. This allows you to call any methods defined on the superclass, but the actual instance is still of the subclass.
Would newEntity have both the common property of entityID as well as the unique property of middleName set correctly?
It sure would. It inherits the instance variables, properties and methods in the superclass.
Rest assured, as far as I can tell this looks sound and is a pattern I've used before.
I do it like this.
// NNEntity.h
#interface NNEntity : NSObject
#property (nonatomic, retain) NSString *entityId;
#end;
// NNEntity.m
#implementation NNEntity
#end;
// NNEntity+KVC.h
#interface NNEnity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
#end
// NNEntity+KVC.m
#implementation NNEntity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// Handle this as appropriate to your app.
// A minimal implementation will throw an exception.
}
#end
And similarly for your various subclasses. You don't (necessarily) need the category on your subclasses.
Then, given NSDictionary *dict with your stuff in it:
NNEntity *entity = [[NNEntity alloc] init];
[entity setValuesForKeysWithDictionary:dict];
Violá! You're done. There are some criticisms of this method, but given a strong implementation of setValue:forUndefinedKey:, I think it's safe and incredibly flexible.
The secrets are in Apple's beautiful Key-Value Coding technology. Essentially, setValuesForKeysWithDictionary: iterates the keys the dict you give it, and for eachinvokes setValue:forKey: in its receiver. It looks something like this (though I'm sure Apple optimizes it under the hood):
-(void)setValuesForKeysWithDictionary:(NSDictionary *)dictionary {
NSArray *keys = [dictionary allKeys];
for (NSString* key in keys) {
[self setValue:[dictionary valueForKey:key] forKey:key];
}
}
I also like this approach because a conversion to CoreData is simple; when you tell CoreData to 'render' your model, it simply overwrites your stubbed model classes, keeping your KVC Category intact. What is more, if your implementation of setValue:forUndefinedKey: is smooth, you can make model changes to your backend without crashing the app (this is a bit of a no-no, but it's not much different from your factory solution).
Of course, I have not addressed your need to selectively choose which class to instantiate. But that is a larger design issue that could be affected even by the design of your API and backend. So I defer.
Also, as you noted in your comment below, the property names must match up. This is a show-stopper for some developers, especially so if you cannot control both the backend and the client.
Give it a try. Feedback is welcome.

iOS JSON serialization for NSObject-based classes

I'd like to JSON-serialize my own custom classes. I'm working in Objective-C / iOS5.
I'd like something to do the following:
Person* person = [self getPerson ]; // Any custom object, NOT based on NSDictionary
NSString* jsonRepresentation = [JsonWriter stringWithObject:person ];
Person* clone = [JsonReader objectFromJson: jsonRepresentation withClass:[Person Class]];
It seems that NSJSONSerialization (and several other libraries) require the 'person' class to be based on NSDictionary etc. I want something that will serialize any custom object that I care to define (within reason).
Let's imagine Person.h looks like this:
#import <Foundation/Foundation.h>
#interface Person : NSObject
#property NSString* firstname;
#property NSString* surname;
#end
I'd like the generated JSON for an instance to look similar to the following:
{"firstname":"Jenson","surname":"Button"}
My app uses ARC. I need something that will both serialise and deserialize using objects.
Many thanks.
This is a tricky one because the only data you can put into JSON are straight up simple objects (think NSString, NSArray, NSNumber…) but not custom classes or scalar types. Why? Without building all sorts of conditional statements to wrap all of those data types into those type of objects, a solution would be something like:
//at the top…
#import <objC/runtime.h>
NSMutableDictionary *muteDictionary = [NSMutableDictionary dictionary];
id YourClass = objc_getClass("YOURCLASSNAME");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(YourClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
SEL propertySelector = NSSelectorFromString(propertyName);
if ([classInstance respondsToSelector:propertySelector]) {
[muteDictionary setValue:[classInstance performSelector:propertySelector] forKey:propertyName];
}
}
NSError *jsonError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:muteDictionary options:0 error:&jsonError];
This is tricky, though because of what I stated before. If you have any scalar types or custom objects, the whole thing comes tumbling down. If it's really critical to get something like this going, I'd suggest looking into investing the time and looking at Ricard's links which allow you to see property types which would assist on the conditional statements needed to wrap the values into NSDictionary-safe objects.
Now you can solve this problem easily using JSONModel. JSONModel is a library that generically serialize/deserialize your object based on Class. You can even use non-nsobject based for property like int, short and float. It can also cater nested-complex JSON.
Deserialize example. By referring to your example, in header file:
#import "JSONModel.h"
#interface Person : JSONModel
#property (nonatomic, strong) NSString* firstname;
#property (nonatomic, strong) NSString* surname;
#end
in implementation file:
#import "JSONModelLib.h"
#import "yourPersonClass.h"
NSString *responseJSON = /*from somewhere*/;
Person *person = [[Person alloc] initWithString:responseJSON error:&err];
if (!err)
{
NSLog(#"%# %#", person.firstname, person.surname):
}
Serialize Example. In implementation file:
#import "JSONModelLib.h"
#import "yourPersonClass.h"
Person *person = [[Person alloc] init];
person.firstname = #"Jenson";
person.surname = #"Uee";
NSLog(#"%#", [person toJSONString]);
maybe this can help JLObjectStrip.
its the same as what jacob said but it iterates even to the property of the class. this will give you dictionary/array then just use sbjson/jsonkit or what ever you prefer to construct your json string.
Try this one BWJSONMatcher
It's really simple as well as convenient.
...
NSString *jsonString = #"{your-json-string}";
YourValueObject *dataModel = [YourValueObject fromJSONString:jsonString];
NSDictionary *jsonObject = #{your-json-object};
YourValueObject *dataModel = [YourValueObject fromJSONObject:jsonObject];
...
YourValueObject *dataModel = instance-of-your-value-object;
NSString *jsonString = [dataModel toJSONString];
NSDictionary *jsonObject = [dataModel toJSONObject];
...
What i do for my objects is i have a method called "toDict" that return a nsdictionary. IN this method i set all attributes i need/want into the dictionary for example
[user setObject:self.first_name forKey:#"first_name"];
[user setObject:self.last_name forKey:#"last_name"];
[user setObject:self.email forKey:#"email"];

NSDictionary add -objectAtIndex by category

I'm writing custom patch for Quartz Composer and I work with structures as input. Structure are NSDictionary in Obj-C so I use NSDictionary's methods to deal with these structures. Depending on how I build these structures key can be NSString type or NSNumber.
Usually QC doesn't give named structures and keys are "0"..."n" or 0...n so I've decided to add -objectAtIndex in a NSDictionary category :
NSDictionary+Utils.h
#import <Foundation/Foundation.h>
#interface NSDictionary (Utils)
- (id)objectAtIndex:(NSInteger)index;
#end
NSDictionary+Utils.m
#import "NSDictionary+Utils.h"
#implementation NSDictionary (Utils)
- (id)objectAtIndex:(NSInteger)index
{
NSString* key = [NSString stringWithFormat:#"%d", index];
return [self objectForKey:key];
}
#end
It works perfectly for one of my project in which I build a structure using Kineme Struc Maker patch.
In another project I use the Queue patch provided by apple. Keys are not NSString type but NSNumber type. I've rewritten the code to be compliant with NSNumber keys :
NSDictionary+Utils.m
#implementation NSDictionary (Utils)
- (id)objectAtIndex:(NSInteger)index
{
NSNumber* key = [NSNumber numberWithInteger:index];
return [self objectForKey:key];
}
#end
Unfortunately it always gives a null value but using :
[self.inputSoundStruct objectForKey:[NSNumber numberWithInteger:0]]
Why does this line of code works but not objectAtIndex ? I must be missing something but what ?

Convert an object into NSDictionary

Is there any generic implementation which converts any Object into NSDictionary, sets all variable names as keys and values as dictionary values?
In order to achieve your objective, you can use Key-Value Coding. This protocol provides a mechanism to set values of object properties based on the names of the properties represented as NSString's rather than calling the accessors directly.
In order for it to work, you need to have defined your objects with accessors that follow the naming conventions (easy enough using properties). You can see the NSKeyValueCoding protocol guide here:
http://bit.ly/es6kyH
And the Key-Value Coding programming guide here:
http://bit.ly/fBY3Qa
You'll still have to do the iteration, but it's a good start.
Solved using SBJSONParser, converted NSObject to JSON Representation and then fetched NSDictionary out of it.
The perfect way to do this is by using a library for serialization/deserialization
many libraries are available but one i like is
JagPropertyConverter
https://github.com/jagill/JAGPropertyConverter
it can convert your Custom object into NSDictionary and vice versa
Assuming
#interface Person : NSObject
#property (nonatomic, retain) NSNumber * age
#property (nonatomic, retain) NSString * address
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * cellNo;
#end
JAGPropertyConverter *converter = [[JAGPropertyConverter alloc]init];
converter.classesToConvert = [NSSet setWithObjects:[Person class], nil];
Person *person = [[Person alloc]init];
person.name = #"name";
person.address = #"address";
person.age = #27;
person.cellNo = #"XXXXXXXXXX";
//For Object to Dictionary
NSDictionary *dictPerson = [converter convertToDictionary:person];
//For Dictionary to Object
Person *person = [[Person alloc]init];
[converter setPropertiesOf:person fromDictionary:dictPerson];
No, you could have everything in your class, e.g. references to other objects and primitives. NS-Dictionary can serialize itself to a NSString and NSString can recreate the dictionary from the string. Best will be you supply your own methods to serialize it.