Subclassing NSDictionary not working - objective-c

I have a dictionary that I read from a plist. I want to create a subclass of NSDictionary to implement something like the following, so that I can avoid using #"key name" everywhere in my source code:
#interface MyDict{
}
-(NSString*) textString;
#end
#implementation MyDict
-(NSString*) textString {
return [self objectForKey:#"textString"];
}
#end
In my other method:
MyDict *d = ... // something i read from plist
NSString *str = [d textString];
When I call the method, the app crashes because of "unrecognized selector textString". What is wrong here?

Just assigning an NSDictionary to a MyDict pointer doesn't make it a MyDict instance.
One way you can do this would be to create a category to add your method to NSDictionary. See http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1 for info.

Your class has no superclass. Also, the conventional wisdom is that it's very difficult to subclass NSDictionary because it is an class cluster. You don't actually get an NSDictionary back when you:
NSDictionary * myDict = [NSDictionary dictionary];
You get a private subclass (NSCFDictionary in this case).
You might want to try defining your own dictionary keys, the way Apple does:
NSString * const MyWonderfulUnicornKey = #"MyWonderfulUnicornKey";

Related

Can i get another object from class method?

So, i want to get NSDictionary from class method, i think it will be like this:
NSDictionary *dictionary = [SomeClass parseJSONAndGetDictionary];
Can someone explain me how i can make it?
in you .h file of your SomeClass declare method like,
+ (NSDictionary*)aClassMethod;
and in your .m file of your SomeClass implement it like it will return NSDictionary something like,
+ (NSDictionary*)population{
// get desired dictionary here and return it
return dictionary ;
}
the you can got dictionary from any class like,
NSDictionary *dictionary = [SomeClass parseJSONAndGetDictionary];
by implementing SomeClass.h file in that class.

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"];

Objective C - respondsToSelector for dynamic properties

I am currently facing the problem to check whether a property of an Object (NSManagedObject) exists or not.
Unfortunately the method
[[MyObject class] respondsToSelector:#selector(myProperty)];
always returns NO.
I think it's because the property generated by CoreData is a new style property ala
#property (nonatomic, strong) NSString *myProperty
So any ideas how to solve this issue?
I would really appreciate all of your suggestions ;)
Thanks in advance!
Alex
[[MyObject class] respondsToSelector:...] asks whether the metaobject responds to that selector. So, in effect, it asks whether there is a class method with that selector. Your code would return YES if you had:
+ (NSString *)myProperty;
It returns NO because you have the equivalent of the instance method:
- (NSString *)myProperty;
You need to call respondsToSelector: on an instance of your class.
You could normally use instancesRespondToSelector: directly on the metaclass (so, [MyObject instancesRespondToSelector:...]) but Core Data synthesises the relevant method implementations only when you create an object, so that's a non-starter. You could however create an instance via the normal NSEntityDescription route and test respondsToSelector: on that.
Since it's all Core Data, an alternative would be to ask the NSManagedObjectModel for the relevant NSEntityDescription via its entitiesByName dictionary and inspect the entity description's propertiesByName dictionary.
The only cases I've required this has been to set things dynamically so I am only looking for the setter. I am just composing the signature for the setter and then testing that it exists and then using it.
NSArray * keys = [myObject allKeys];
for(NSString * key in keys)
{
NSString * string = [NSString stringWithFormat:#"set%#:", [key capitalizedString]];
SEL selector = NSSelectorFromString(string);
if([myObject respondsToSelector:selector] == YES)
{
id object = [dict objectForKey:key];
// To massage the compiler's warnings avoid performSelector
IMP imp = [card methodForSelector:selector];
void (*method)(id, SEL, id) = (void *)imp;
method(myObject, selector, object);
}
}
This code satisfies a need where you may not be digesting all the data you receive in the dictionary.
In this case it was sparse json, so some data may not always exist in the json so stepping thru myObjects attributes looking for their corresponding key would just be a lot of wasted effort.
Are you synthesizing the property in the class file?
#interface SomeClass : NSObject
{
#property (nonatomic, strong) NSString *myProperty
}
#end
#implementation SomeClass
#synthesize myProperty;
#end

Objective C initialization of a derived NSObject and further assignation

I'm not sure how to manage this, as objective-c is wierd enough for me
I'm have this derived class
#interface DoctorsSet : NSObject { NSString *tableid;
NSString *doctor_name;
NSString *doctor_surname;
NSString *city;
NSString *State;
NSString *phone; }
It has a custom constructor on which I'm initializing the properties as params...
THe problem is I have several functions that return this type, so how so I assign to a temporary local variable this type, or if my data comes from a NSMutableArray and I want to get that object at index ID
here are the 2 cases which I couldn't handle, because on assign it give an access error
NSMutableDictionary *doctors_set;
for(i=[doctors_sets count]-1;i>=0;i--) {
//this doesn't work
DoctorsSet * set=[doctors_set objectAtIndex:i];
}
i don't want to use for(DoctorsSet *set in doctors_sets)
because i want to pass the array in the reverse order....
If the end goal is to go in reverse use
for (DoctorsSet *set in [doctors_sets reverseObjectEnumerator])

Objective C - How to add a method to an existing class?

How can i add a new method to NSString class.
I need to create a method that get's called on a string and returns an NSDictionary.
I know that i can simply create a function that gets a string and return an nsdictionary, but i want to know how to add it to an existing class.
NSString *myStr = #"some json string";
NSDictionary *dictionary = [myStr getJSONData];
You can use Objective-C categories. For example to add on to NSString define the following in a new .h/.m file:
#interface NSString (CategoryName)
-(NSString *) aNewMethod;
#end