Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Objective-C Categories == Groovy Expando Mechanism

DZone's Guide to

Objective-C Categories == Groovy Expando Mechanism

· Mobile Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

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]];
  }
  free(properties);
  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 :)

Cheers,
Łukasz

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

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

{{ parent.tldr }}

{{ parent.urlSource.name }}