Over a million developers have joined DZone.

Objective-C Categories == Groovy Expando Mechanism

DZone 's Guide to

Objective-C Categories == Groovy Expando Mechanism

· Mobile Zone ·
Free Resource

Long live dynamic languages! It's a short post glorifying dynamic languages :)

(BTW: do you remember my previous post about Groovy: 21 things I like and don't like about Groovy? - there is an example of Groovy expando mechanism)

I know and use Objective-C categories. I use them to, for example, re-implement methods that are already provided.

But only yesterday, while writing some iPhone piece of code using SBJSON library I realised that in fact Objective-C category mechanism is the same as Groovy expando mechanism.

SBJSON example

For example SBJSON adds JSONRepresentation method to NSObject. But in fact it only works for dictionaries and arrays so you have to invoke it this way:

User *user = [User new];
user.emai = @"lukasz@example.com";
user.password = @"super_secret";
NSDictionary *userDictionary = [user dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"email",@"password",nil]]; 
NSString *userDictionary = [person JSONRepresentation];

But I (with a help of categories of course!) went one step farther :) I used Apple Runtime library to dynamically scan for all properties in given object, create dictionary and then create JSON string in one step.

Enhanced JSONRepresentation method

I pointed my browser to Mac OS X Reference Library - Objective-C Runtime Reference.

Based on the reference I changed the original JSONRepresentation implementation (located in NSObject+SBJSON.m file) to this:

#import <Foundation/NSObjCRuntime.h>
#import <objc/objc.h>
#import <objc/runtime.h>

- (NSString *)JSONRepresentation {
    SBJsonWriter *jsonWriter = [SBJsonWriter new];    
    NSString *json = nil;
 if ([self isKindOfClass:[NSDictionary class]] || [self isKindOfClass:[NSArray class]]) {
  json = [jsonWriter stringWithObject:self];
 } else {
  NSUInteger propertyCount = 0;
  objc_property_t* properties = class_copyPropertyList([self class], &propertyCount);
  NSMutableArray *keys = [NSMutableArray new];
  for (NSUInteger i = 0; i < propertyCount; i++) {
   objc_property_t property = *(properties + i);
   [keys addObject:[NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding]];
  NSDictionary *dictionary = [self dictionaryWithValuesForKeys:keys];
  json = [jsonWriter stringWithObject:dictionary];
    if (!json)
        NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]);
    [jsonWriter release];
    return json;

Works like a charm :) Now instead of explicitly creating NSDictionary all you have to do is:

[user JSONRepresentation];

Nice :)



Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}