Objective-C for Java (and Ruby) Developers – Part 2

28 Feb 2010 – Denver, CO

Meta-data

No discussion about a language would be complete without covering the ability to navigate around its meta and find information about its classes and methods.

Lets start with Ruby, which, as is usually the case, everything is sweet:

 
	class Philly < String
	  def initialize
	    @var = ""
	  end
	  def custom_method 
	    "Philly"
	  end
	end

	philly = Philly.new

	p philly.class
	p philly.methods
	p philly.instance_variables
	p philly.kind_of?(String)

Takes a couple more lines of code in Java, but still life is good:

 
	import java.util.*;
	import java.lang.reflect.*;
	import java.io.*;

	public class Philly extends StringWriter
	{		
		public String var;
		public void custom_method()
		{
		}

		public static void main(String[] args) 
			throws InterruptedException
		{
			Object p = new Philly();
			Class c = p.getClass();
			System.out.println(c.getName());

			Method[] m = c.getMethods();
			Iterator it = Arrays.asList(m).iterator();
			while (it.hasNext())
			{
				System.out.println(it.next());
			}

			Field[] f = c.getFields();
			it = Arrays.asList(f).iterator();
			while (it.hasNext())
			{
				System.out.println(it.next());
			}

			System.out.println(StringWriter.class.
				isAssignableFrom(c));
		}
	}

Note that the String class is Final in Java so we couldn’t over-ride it. I just over-rode StringWriter to get the message across, you get the general point.

Which takes us finally to Objective-C, where things are longer still, but not too bad. Note that we do have to worry about freeing up any memory that was allocated in our calls.

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

@interface Philly : NSString
{
	int var;
}

-(void) custom_method;

@end

@implementation Philly

-(void) custom_method 
{
}

@end

int main (int argc, const char * argv[]) 
{
    NSAutoreleasePool * pool = 
		[[NSAutoreleasePool alloc] init];

	Philly *p = [[Philly alloc] init];
    
	// the class
	NSLog(@"%@", [p class]);

	// methods
	unsigned int count = 0;
	Method *methods = class_copyMethodList(
		[p class], &count);
	for (int i = 0; i < count; i++)
	{	
		SEL selector = method_getName(methods[i]); 
		NSLog(@"%s", selector);
	}	
	
	// instance variables
	Ivar *vars = class_copyIvarList(
		[p class], &count);
	for (int i = 0; i < count; i++)
	{	
		NSLog(@"%s", ivar_getName(vars[i]));
	}
	
	// kindof/superclass
	NSLog(@"%@", [[p class] isSubclassOfClass: 
	 [NSString class]] ? @"true" : @"false");
	
	free(methods);
	free(vars);
	[p release];
    [pool drain];
    return 0;
}

Now this is a little interesting, because the interesting calls in this example (e.g. class_copyMethodList) calls come from the Mac OS X implementation of the Objective-C runtime platform, so things may look differently for Linux or a GNU-compiler based platform. You can read more about it here.

Categories

Lets spend a second talking about the ‘Fragile Base Class’ problem in object orientated programming. This basically refers to the issue where (to quote wikipedia) “base classes (superclasses) are considered ‘fragile’ because seemingly safe modifications to a base class, when inherited by the derived classes, may cause the derived classes to malfunction”. So in essence if I create a base class which is then sub-classed repeatedly (or perhaps even once), its difficult for me to make any changes to the base class because I have limited visibility into the effects that change will have to all of the sub-classes.

Each language gets it own flavor of solution to deal with this. In Java (and generally in the OO world) we are told to program to interfaces, not to classes/implementations. We are also given the ‘Final’ keyword to lock super-classes down. In Ruby we get Mixins, as we as (arguably) the ability to ‘Monkey-Patch’. In Objective-C, we get Categories.

A Category is at its simplest, the ability to add methods (not variables) to an interface/implementation without necessarily subclassing. Its an extension to a class, and its possible to have multiple categories for the same class. An example:

 
	@interface Philly : NSString
	{
		int var;
	}

	-(void) custom_method;

	@end

	@implementation Philly

	-(void) custom_method 
	{
	}

	@end

	@interface Philly (MyCategory)

	-(void) category_method;

	@end

	@implementation Philly (MyCategory)

	-(void) category_method
	{
	}

	@end

	@interface Philly (SecondCategory)

	-(void) second_category_method;

	@end

	@implementation Philly (SecondCategory)

	-(void) second_category_method
	{
	}

	@end

This effectively allows us to add methods to a super-class, without having to modify the superclass directly.

Protocols

A protocol is, at its simplest, very similar to a Java Interface. It enables us to define a list of methods that have to be implemented. If a Class decides to ‘conform’ to that protocol, it must implement the listed methods. In short:

 
@protocol MyProtocol

-(void) protocol_method;

@end

@interface Philly <MyProtocol>
{
	int var;
}

-(void) custom_method;

@end

@implementation Philly

-(void) custom_method 
{
}

-(void) protocol_method
{
}

@end

Early flight to Dallas tomorrow morning. Spending the week (hopefully) getting my Java on!