Jackson equivalent for iPhone? - iphone

I have used Jackson extensively on the Server side to convert from POJOs to JSON and was wondering if there is a similar library for Objective C/iPhone SDK and vice versa. Objective C does provide reflection so it should be possible to make something similar to Jackson.

You might try GoldenFleece, which converts between JSON and Objective-C objects using a convention-over-configuration pattern inspired by Jackson.

The new iOS 5 APIs provide a great facility in reading/writing JSON. These are essentially a rehash of the TouchJSON library which you can use in iOS 4. While I haven't seen much out there that will generate POCO objects from an example payload, you can create classes that are just a facade for an NSDictionary instance that the aforementioned libraries will return.
For example:
#interface PBPhoto : NSObject {
NSDictionary* data_;
}
#property (nonatomic, retain, readonly) NSDictionary *data;
- (NSString*) photoId;
- (NSString*) userId;
- (NSString*) user;
- (NSString*) title;
- (id) initWithData:(NSDictionary*)data;
#end
Implementation:
#import "PBPhoto.h"
#define PHOTO_ID #"id"
#define USER_ID #"user_id"
#define USER #"user"
#define TITLE #"title"
#implementation PBPhoto
#synthesize data = data_;
- (id) initWithData:(NSDictionary*)data {
if ((self = [super init])) {
self.data = data;
}
return self;
}
- (NSString*) photoId {
return [super.data objectForKey:PHOTO_ID];
}
- (NSString*) userId {
return [self.data objectForKey:USER_ID];
}
- (NSString*) user {
return [self.data objectForKey:USER];
}
- (NSString*) title {
return [self.data objectForKey:TITLE];
}
- (void) dealloc {
[data_ release];
[super dealloc];
}
#end

That Objective-C provides reflection may be the understatement of the year, but a lot of stuff is exposed only by the low-level C runtime and therefore is a little obtuse.
Assuming you want to take an arbitrary object and turn it into JSON, probably the smart thing is to create an NSDictionary as an intermediary, then pass it off to NSJSONSerialization (or else construct the string yourself because all of the third party libraries are quite heavyweight owing to the burden of being able to deserialise).
So, for example:
- (NSDictionary *)dictionaryOfPropertiesForObject:(id)object
{
// somewhere to store the results
NSMutableDictionary *result = [NSMutableDictionary dictionary];
// we'll grab properties for this class and every superclass
// other than NSObject
Class classOfObject = [object class];
while(![classOfObject isEqual:[NSObject class]])
{
// ask the runtime to give us a C array of the properties defined
// for this class (which doesn't include those for the superclass)
unsigned int numberOfProperties;
objc_property_t *properties =
class_copyPropertyList(classOfObject, &numberOfProperties);
// go through each property in turn...
for(
int propertyNumber = 0;
propertyNumber < numberOfProperties;
propertyNumber++)
{
// get the name and convert it to an NSString
NSString *nameOfProperty = [NSString stringWithUTF8String:
property_getName(properties[propertyNumber])];
// use key-value coding to get the property value
id propertyValue = [object valueForKey:nameOfProperty];
// add the value to the dictionary —
// we'll want to transmit NULLs, even though an NSDictionary
// can't store nils
[result
setObject:propertyValue ? propertyValue : [NSNull null]
forKey:nameOfProperty];
}
// we took a copy of the property list, so...
free(properties);
// we'll want to consider the superclass too
classOfObject = [classOfObject superclass];
}
// return the dictionary
return result;
}
Then you can use + dataWithJSONObject:options:error: on NSJSONSerialization with the returned dictionary.
To go the other way, I guess you'd use the key-value coding setValue:forKey: method, getting keys and values from a dictionary via allKeys and valueForKey:.

Related

Subclass NSString

I want to add a property to a NSString object. For this reason I want to subclass it.
I try to make something like this:
#interface MyString : NSString
#property (nonatomic) NSInteger userId;
#end
so then I can do
MyString *testString = [[MyString alloc] init];
testString = [MyString stringWithFormat:#"hello"];
testString.userId = 2;
NSLog(#"testString: %#", testString); //-> Want it to return "testString: hello"
NSLog(#"userId: %d", testString.userId); //-> Want it to return "userId: 2"
I don't know how to subclass NSString (create storage facilities, override some methods (length, characterAtIndex). Have an idea?
Don't try to subclass NSString to do this. Create an entirely new class that is a subclass of NSObject and give it 2 properties (and a set of methods to access the properties if you want to).
Trying to use NSString is overly complicated and not appropriate.
For this line:
NSLog(#"testString: %#", testString);
all you need to do is implement the description method on your custom class to return the string property. Then the string will be printed when you use NSLog.
Subclassing class cluster classes is tricky, as you've discovered. Which is why, generally, it is pretty much never done.
Instead, create a class that encapsulates two strings; the string that would point to #"hello" in your example and the userId.
#interface MyThingy:NSObject
#property(copy) NSString *stringData;
#property(copy) NSString *userId;
#end
... etc ...
This will be far more flexible and it will be easier to refactor in the future.
BTW, this doesn't make sense:
MyString *testString = [[MyString alloc] init];
testString = [MyString stringWithFormat:#"hello"];
Under manual retain/release, it is a leak. Under ARC, it is a purposeless allocation.
Why don't you use NSMutablestring in this you can use appendString method in which you can add your any stringValue and then just pass the same to your string.
Try this category. You can add any kind of custom object to anything coming from NSObject - basically any class - by use of a key. Retrieve the object using that key. I think I got this from someone (found it) here on stackoverflow.
Header:
//
// NSObject+arbitraryobjectonanynsobjectlol.h
//
//
// Created by someone on 2/21/14.
// Copyright (c) 2014 someone. All rights reserved.
//
#import <Foundation/Foundation.h>
// https://stackoverflow.com/a/10319083/129202
#interface NSObject (arbitraryobjectonanynsobjectlol)
- (id)associativeObjectForKey: (NSString *)key;
- (void)setAssociativeObject: (id)object forKey: (NSString *)key;
#end
And the implementation:
//
// NSObject+arbitraryobjectonanynsobjectlol.m
// someone
//
// Created by someone on 2/21/14.
// Copyright (c) 2014 someone. All rights reserved.
//
#import "NSObject+arbitraryobjectonanynsobjectlol.h"
#import <objc/runtime.h>
#implementation NSObject (arbitraryobjectonanynsobjectlol)
static char associativeObjectsKey;
- (id)associativeObjectForKey: (NSString *)key {
NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
return [dict objectForKey: key];
}
- (void)setAssociativeObject: (id)object forKey: (NSString *)key {
NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
if (!dict) {
dict = [[NSMutableDictionary alloc] init];
objc_setAssociatedObject(self, &associativeObjectsKey, dict, OBJC_ASSOCIATION_RETAIN);
} [dict setObject: object forKey: key];
}
#end

Accessing C arrays(int[], float[], etc..) using Objective-C runtime

I'm trying to save all the variables in my class into NSUserDefaults using objc/runtime. And below is the code I'm using.
NSUInteger count;
Ivar *iVars = class_copyIvarList([self class], &count);
for (NSUInteger i=0; i<count; i++)
{
Ivar var = iVars[i];
NSString *varName = [NSString stringWithCString:ivar_getName(var) encoding:NSUTF8StringEncoding];
NSString *varType = [NSString stringWithCString:ivar_getTypeEncoding(var) encoding:NSUTF8StringEncoding];
if([varType hasPrefix:#"["])
{
NSLog(#"Array");
id var1 = [_manager valueForKey:varName];
NSLog(#"--- %#", var1);
NSData *data = [NSData dataWithBytes:&([_manager valueForKey:varName]) length:sizeof([_manager valueForKey:varName])]
[[NSUserDefaults standardUserDefaults] setObject:[_manager valueForKey:varName] forKey:varName];
}
else
{
NSLog(#"NonArray");
NSLog(#"--- %#", [_manager valueForKey:varName]);
[[NSUserDefaults standardUserDefaults] setObject:[_manager valueForKey:varName] forKey:varName];
}
}
free(iVars);
The problem is that, when there are only primitive datatypes, the above code works just fine. But, when I try to access a array variable like int[], or float[], it gets crashed with SIGABRT. it is not showing any other messages.
valueForKey doesn't return any values for C arrays.
If anybody know how to load values for C-arrays in runtime, please help.
Thanks in advance,
Suran
Unless you always provide a paired length method, your program will never know the length of the array returned. So... you will need to do some work someplace to accomplish this without a crash.
If I really wanted to do what you're doing, I would make the class itself create the array, providing NSData. If this is common, you may want to use a convention:
- (int*)pixelBuffer;
- (NSData *)pixelBufferForSerialization; // << returns a deep copy of
// self.pixelBuffer as an
// NSData instance.
So your above implementation would see that the property defines a scalar array, and then request NSData * data = obj.pixelBufferForSerialization; instead of trying to produce the data itself.
Update
It's best to let the class do it. Here's how to create NSData using such an array:
#interface DataManager : NSObject
{
#private
int* things;
size_t nThings;
}
- (int*)things;
- (NSData *)thingsAsNSData;
#end
#implementation DataManager
- (int*)things
{
return things;
}
- (NSData *)thingsAsNSData
{
// note: you may need to choose an endianness for serialization
if (0 == nThings) return [NSData data];w
return [NSData dataWithBytes:things length:nThings * sizeof(things[0])];
}
#end
Again - you want the class to create the data because it knows its own structure best.

When declare a property(retain) in objective c, what's the default implementation of set/get method

I am a newer to objective c. I have read the memory management document on apple's "Memory Management Rules". But I am still not very clear about how to manage reference for a property.
What's the default implementation of set/get access methods for a property declared with "retain" annotation?
This is my assuming, please give some comments. Thanks.
#interface SubClass : NSObject {
NSString * _name;
}
... ...
#property (nonatomic, retain) NSString * name;
... ...
#end
-(NSString *) setName {
return _name;
}
-(void) setName: (NSString *) pName{
// the correct version of default set method for retain
if( _name != pName ) {
[_name release];
_name = [pName retain];
}
}
So the dealloc method, is this ok?
- (void)dealloc {
self.name = nil; // or [_name release], _name = nil;
}
As Matteo Alessani says, you can simply synthesize the property to get the default implementations.
For reference, this is what's generated (I got this from reading Objective-C Declared Properties and piecing information together):
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)aName {
if (_name != aName) {
[_name release];
_name = [aName retain];
}
}
You can use synthesize in your implementation file:
#implementation SubClass
#synthesize name = _name;
#end
Automatically you get the default getter and setter.
As Matteo said you can synthesize accessor methods automatically.
But speaking about implementation details:
yes getter method may look like (but note the correct name):
-(NSString *) name {
return _name;
}
or to handle the case when you use name value and object that holds it gets deallocated:
-(NSString *) name {
return [[_name retain] autorelease];
}
setter method:
-(void) setName: (NSString *) pName{
NSString *temp = [pName retain];
[_name release];
_name = temp;
}
dealloc. Your implementation is ok, but as calling properties may cause some side effects relying that all fields in your object are valid (which may not be so in dealloc method) it may be better to release ivar directly.
Your setter example is wrong as you don't need to handle nil case (actually in your code you can never set name value to nil), but you need to handle the case when property is set to the same object.

#dynamic properties and its usage?

Can anyone give me clear picture about dynamic property and its usage? y not use the usual #property everywhere?
Dynamic properties are used when you don't provide an implementation at compile time, but ensure that one exists at runtime. Being a dynamic language, Objective-C can respond to messages at runtime, even if the class doesn't have an implementation at compile time.
Here's a contrived example: Let's say you have a Book class, backed by an NSMutableDictionary that contains the keys title and author. However, you want Book to respond to title and author as well, and have them as properties; title and author will grab the appropriate value from the dictionary, and setTitle: and setAuthor: will change the value stored in the dictionary. You could do so with this code:
#import <Foundation/Foundation.h>
#interface Book : NSObject
{
NSMutableDictionary *data;
}
#property (retain) NSString *title;
#property (retain) NSString *author;
#end
#implementation Book
#dynamic title, author;
- (id)init
{
if ((self = [super init])) {
data = [[NSMutableDictionary alloc] init];
[data setObject:#"Tom Sawyer" forKey:#"title"];
[data setObject:#"Mark Twain" forKey:#"author"];
}
return self;
}
- (void)dealloc
{
[data release];
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
NSString *sel = NSStringFromSelector(selector);
if ([sel rangeOfString:#"set"].location == 0) {
return [NSMethodSignature signatureWithObjCTypes:"v#:#"];
} else {
return [NSMethodSignature signatureWithObjCTypes:"##:"];
}
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSString *key = NSStringFromSelector([invocation selector]);
if ([key rangeOfString:#"set"].location == 0) {
key = [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString];
NSString *obj;
[invocation getArgument:&obj atIndex:2];
[data setObject:obj forKey:key];
} else {
NSString *obj = [data objectForKey:key];
[invocation setReturnValue:&obj];
}
}
#end
int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Book *book = [[Book alloc] init];
printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
book.title = #"1984";
book.author = #"George Orwell";
printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
[book release];
[pool release];
return 0;
}
Note the the methods are "created" at runtime via forwardInvocation:; hence, title and author are dynamic properties.
(This isn't the best example, but I think it gets the point across.)
#dynamic thing; is merely a way to inform the system not to generate getters/setters for the thing, that you (or someone else) will provide them for you—As in, they'll be there at runtime.
This is in contrast to #synthesize which tells the compiler to generate the getter/setter (as appropriate) for you.
#dynamic is (in my experience) used primarily in conjunction with Core Data and subclasses of NSManagedObject. To quote Marcus Zarra's Core Data,
By declaring them
[attributes/relationships], we are
telling the compiler to ignore any
warnings associated with there
properties because we "promise" to
generate them at runtime. Naturally,
if the turn up missing at runtime,
then our application is going to
crash.

Filling class variables from an NSDictionary in a loop

I would like to fill in the class variables in a loop from an dictionary. What I want to do is having the dictionary key as a class variable and assign the class variable (the dictionary key) the value from dictionary... something like this:
+(void) initWithDictionary:(NSDictionary *)dic {
MyClass *classInstance = [[[self alloc] init] autorelease];
NSArray *allKeys = [dic allKeys];
for(NSUInteger i = 0; i < [allKeys count]; i++)
{
id classVariable = [allKeys objectAtIndex:i];
classInstance.classVariable = [dic objectForKey:[allKeys objectAtIndex:i]];
}
return classInstance;
}
It does not work, because I do not know how to assign the class variable from the string.
Thanks for answer, I am returning a JSON string that gives me an NSDictionary with keys and values. I am trying to fill this values to my class, let's say DetailObject. I want to use later in the project the DetailObject.id, DetailObject.description, etc. I would like to do it in a loop, becouse now I have to write this:
+ (id) initWithDiccionary :(NSDictionary *)dic//;
{
//Instantiating an object of this class... that's okay.
DetailObject *classInstance = [[[self alloc] init] autorelease];
classInstance.id = [dic objectForKey#"id"];
classInstance.desc = [dic objectForKey#"desc"];
etc... etc...
return classInstance;
}
What I want is to parse the dictionary from JSON to my object and respective variables and values that comes from dictionary in a loop, because if the JSON dictionary changes, I just add the new class variable with the same name of the returned dictionary key...
I do not know if I have explained it well...
Your question is very very unclear and I have no idea what you're trying to do or why. But just looking at your code I can tell you already that it's definitely not doing what you want.
//There should be no semicolon after "dic" below.
//Also, you should be returning a MyClass or an id.
- (id) initWithDiccionary :(NSDictionary *)dic//;
{
//Instantiating an object of this class... that's okay.
MyClass *classInstance = [[[self alloc] init] autorelease];
//Getting all the keys from the dictionary, seems fine...
NSArray *allKeys = [dic allKeys];
//Looping through all the keys in the dictionary, seems okay...
for(NSUInteger i = 0; i < [allKeys count]; i++)
{
//Storing the current key.
id classVariable = [allKeys objectAtIndex:i];
//Assigning the class's property "classVariable" to match the current key's value.
//No reason to say "[allKeys objectAtIndex:i]" again, though.
classInstance.classVariable = [dic objectForKey:classVariable];
}
//Returning something when you have no return type above (void) is wrong.
return classInstance;
}
Your code will just assign classInstance.classVariable to be equal to [allKeys objectAtIndex:[allKeys count]-1]. Your loop is pointless.
After I actually annotated your code though I think I have some idea of what you want. Basically you want to assign the variables with names matching the keys in the dictionary the values in the dictionary. i.e. if there is a key called "superKey" then you want to find the variable within classInstance (classInstance.superKey) and assign it the value in the dictionary that matches superKey. That's what you want, right?
Well, the only way I know of to do that is to use a big switch statement or a bunch of if statements. Make some function within MyClass like this:
- (void) assignProperty:(id)property toValue:(id)value
{
if (property == #"superKey")
{
self.superKey = value;
}
else if (property == #"lameKey")
{
self.lameKey = value;
}
//etc.
}
Then you just call [classInstance assignProperty:classVariable toValue:[doc objectForKey:classVariable]] and the job will be done.
But having told you all that...
Why would you ever want to do what you're doing? Want to know a much better way of doing this? Give MyClass its own NSDictionary. Basically all you are doing is defeating the entire purpose of the dictionary. Why? They are incredibly fast to access and can store whatever you want. There is no reason not to use one. So just do this:
- (id) initWithDiccionary :(NSDictionary *)dic
{
MyClass *classInstance = [[[self alloc] init] autorelease];
classInstance.dictionary = dic;
return classInstance;
}
Voila.
Enter Key-Value Coding. The following is an example of how you could achieve your desired outcome:
#interface MyClass : NSObject
#property (nonatomic, retain) NSString *aString;
#property (nonatomic, retain) NSNumber *aNumber;
#property (nonatomic, retain) NSString *yetAnother;
- (id)initWithDictionary:(NSDictionary *)dictionary;
#end
#implementation MyClass
#synthesize aString;
#synthesize aNumber;
#synthesize yetAnother;
- (id)initWithDictionary:(NSDictionary *)dictionary {
if ((self = [super init])) {
[self setValuesForKeysWithDictionary:dictionary];
}
return self;
}
// dealloc is left as an exercise for the reader
#end
You could use this class as follows:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"my string", #"aString",
[NSNumber numberWithInt:42], #"aNumber",
#"strings!", #"yetAnother", nil];
MyClass *myClass = [[MyClass alloc] initWithDictionary:dictionary] autorelease];
// yay!
You can thank Objective-C's dynamism for that. :)