Adventures in the transition from C to Cocoa.

Tuesday, November 27, 2007

Too much, Too little

Objective-C 2.0 has completely changed the game (and rendered most of the earlier gdb tricks mentioned to no longer work as well). That said, it has also added some pretty slick new features that I hope I'll be able to give justice to once I get some more free time and some more coherent thoughts.

Just thought I'd let y'all know where things were.

Thursday, November 1, 2007

Best console log message ever

I was put between a rock and a hard place. Basically, I had to call a method on a class that isn't exported (i.e. I'm in plugin-space, and it needs to invoke something on an application-internal class that isn't exported). Through some trickery, I was able to get it working (man I love objective-C!). However, inserting the plugin into an application that doesn't have such a class results in an amazing console error that I've never seen before:


Nov 1 18:33:02 phendrana Photo Booth[33276]: *** NSInvocation: warning: object 0xfce0e0 of class 'specialInternalClass' does not implement methodSignatureForSelector: -- trouble ahead
Nov 1 18:33:02 phendrana Photo Booth[33276]: *** NSInvocation: warning: object 0xfce0e0 of class 'specialInternalClass' does not implement doesNotRecognizeSelector: -- abort


that "trouble ahead" part is awesome. I think it happens to any OC object that doesn't inherit from NSObject, but gets treated like it does. Fun stuff, that :)

Wednesday, October 31, 2007

NSInvocation and version detection

After upgrading from Tiger to Leopard, We've had to deal with several interface changes (mostly because we're using undocumented API/SPI stuff). To make code that still works and compiles on both, we need to create dynamic messages to get past the compiler checks and to use different objects/methods depending on the OS version.

Solving version detection is trivial. There are a few places that document it, but they miss what I consider to be the simplest and most reliable way:


NSData *sysVerData = [[NSData alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
NSDictionary *sysVer = [NSPropertyListSerialization propertyListFromData: sysVerData
mutabilityOption: NSPropertyListImmutable
format: NULL errorDescription: &errorString];
NSComparisonResult compare = [[sysVer objectForKey:@"ProductVersion"] compare:@"10.5"];


That's right. we get our information from the same place as sw_vers. If you think your app will be used on OS X Server, you'll want to change "SystemVersion.plist" to "ServerVersion.plist".

Then, on to NSInvocation.

NSInvocation is a way to invoke methods on objects dynamically. It's a bit tricky, and obviously a bit dangerous. However, with proper checking you can be perfectly safe.

Here's a trivial example of NSInvocation.


#import

@interface anObject : NSObject
-(void) aMethod:(NSString*)arg;
@end

@implementation anObject
-(void) aMethod:(NSString*)arg
{
NSLog(@"aMethod with %08x (%@) %@",arg, [arg className], arg);
}
@end

int main()
{
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
NSString *arg = @"normal";

anObject *a = [[anObject alloc] init];

[a aMethod:nil];
[a aMethod:arg];

NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[anObject instanceMethodSignatureForSelector:@selector(aMethod:)]];
[inv setSelector:@selector(aMethod:)];
[inv setTarget: a];
NSLog(@"built invocation %08x",inv);

[inv setArgument:&arg atIndex:2];

NSLog(@"Set argument %08x",(void*)arg);

[inv invoke];

[p release];
return 0;
}


Important note that I ran into: when using [NSInvocation setArgument:..] objects need to be prefixed with an ampersand, "&". Without this, you'll get wonky results. If you're passing non-objects, you shouldn't use the ampersand.

There are a bunch of checking methods to see how many args a method supports and all that good stuff. You should really read the Documentation to get a good handle on what's going on.

Saturday, October 13, 2007

More gdb-jutsu, 20071013

I guess, since Cocoa is already fairly well covered by a billion sources (including Apple's examples in /Developer/Examples/ stuff, which gives a decent introduction to most technologies available), that I'll shift focus somewhat into the darker side of Cocoa development: debugging, reverse engineering, and modifying applications.

I've spent an embarrassing amount of time reverse engineering a couple programs lately, and I've discovered a couple tips that can help us in this adventure.

First, a handy list of tools:


  • ClassDump

  • OCDisasm

  • gdb



The first two are amazingly handy. ClassDump basically takes an existing framework, and generates all the header files for interacting with the objects used in it. This includes the spiffy undocumented features Apple uses to make their applications spiffier than everyone else's. I'll probably do some exploring here as I transition into GUI stuff from plugin stuff as time goes on.

OCDisasm is a tender little program. It's unfinished, and probably abandoned. However, it's still handy (at least, until leopard comes out, then it will be useless). OCDisasm takes an application, and provides you with the disassembled methods used on the objects. The nice part is that it interprets common constructs with a bit of intelligence most of the time. The handiest feature I've grown to enjoy is the automatic method name placed inline in the code.

The unfortunate part is that OCDisasm only handles the PPC branch of an application. Since I know very little PPC assembly, it is of limited use in non-trivial code.

This is where tonight's gdb-jutsu comes in to play.

When disassembling a function using x/i [address] in gdb, you get unadorned disassembled output on the screen. It usually looks something like this:


0x4f9cf47 <-[SomeObject someMethod:arg:arg2:]+652>: mov 268094972(%ebx),%eax
0x4f9cf4d <-[SomeObject someMethod:arg:arg2:]+658>: mov %eax,4(%esp)
0x4f9cf51 <-[SomeObject someMethod:arg:arg2:]+662>: mov %edi,(%esp)
0x4f9cf54 <-[SomeObject someMethod:arg:arg2:]+665>: call 0x14f45032


The first column is the address in memory. The second column, between the < and >, is the method plus offset (how far into the function, in bytes). And finally, the disassembled code.

Messages are sent to objects using the dyld_stub_objc_msgSend function, seen at the end there. While it looks nothing like its pretty Objective-C counterpart, that's how it works in low-level space.

The unfortunate part is that All messages look like that (and even some functions, particularly CoreGraphics stuff), so it's difficult to tell which message an object is getting.

Thankfully, figuring this information out is quite simple, and lies in the preceding instructions.

Objective-C messages have selectors, which are stored as strings in the executable file. When an dyld_stub_objc_msgSend is called, it takes this selector as one of its arguments. Specifically, stuff that winds up landing at 4(%esp) ends up being our selector.

So, let's start looking at what gets put there. As you probably noticed, a few instructions above the call we have %eax land there. And one instruction before that, we have 268094972(%ebx) land in %eax. With just this knowledge, we can find our selector using this handy command:


(gdb) x/s *($ebx+268094972)
0x4ff0f04 <__FUNCTION__.100691+1516>: "CGLPixelFormatObj"


As you can see, we examine the data located where the program loads the selector from, and we can see our selector as text. Simple as that!

With a bit of prodding, it's also possible to grab other data types using similar methods. However, there isn't a simple rule to extract data, so you might need to play with it some to get it to work. I'll try to explain this more in a future article.

Sunday, October 7, 2007

gdb-jutsu

gdb is a debugger used to find (and hopefully fix!) bugs in programs you're writing. However, it also works on programs you aren't writing (i.e. you don't have the source code, and thus probably can't fix bugs without some super heavy lifting). Since I've normally used it with C/C++ programs, I'm more familiar with those usages than with my current Objective-C usage, which has some different semantics.

The coolest thing ever that I discovered was this (brace yourself):
(gdb) call (char*)[0x3018 UTF8String]
2007-09-09 21:32:23.311 paramsTest[4759] *** _NSAutoreleaseNoPool(): Object 0x4081f0 of class NSCFData autoreleased with no pool in place - just leaking
$4 = 0x408210 "coooool!"


Ignoring the "2007-09... - just leaking" part (which is a message from the program itself, not from gdb), we have this:

(gdb) call (char*)[0x3018 UTF8String]
$4 = 0x408210 "coooool!"


The reason why this is incomprehensibly cool is this: the little 0x3018. Normally you'd have to do something like this: [someString UTF8String] to get useful information. But if you don't have the name of "someString", that's kind of difficult. But 0x3018, that's the address of the object, and anyone can get an object's address. Of course, internally they're the exact same thing, so it's not really doing anything magical. It's just the simplicity with which it works that interests me.

(The syntax here is something like this: [{object} {method}] where object is some object you're doing something with, and method is what the "something" you're doing. In this example, the object would be "someString", and the method would be "UTF8String" which provides us with the UTF8-encoded version of the contents of the string. In English, we're asking the string to tell us what it looks like if we printed it on screen.)

The coolness continues: what if we don't even have the address of the object, but know which argument it is to the current method? This is a pretty typical situation when we're breaking on a certain method's invocation. In this case, we have to use our trusty rusty stack pointer!

In Objective-C, our stack has extra data tossed in for the ObjectiveC runtime. In contrast, C/C++ arguments pretty much correspond 1-to-1 with items on the stack. In Objective-C, ebp+0 is our stack frame or something? I don't really know what it points to, but it's somewhere on the stack. ebp+4 is our return address, ebp+8 is our object's self pointer and ebp+12 is our selector, or method. Our first argument starts at ebp+16, and from there each argument is +4 more. This means arg2 would be at ebp+20, etc. In this example, we'll want to inspect the second argument. we also don't want to fiddle around with extracting the address manually. That's what the computer is there for anyway, isn't it? Let's see a demo:

(gdb) call (char*)[*(int)($ebp+20) UTF8String]
$37 = 0x407b10 "coooool!"


Woah, the same thing! you can see the ebp+20 in there too, if you look closely.

A few data points about that command. "(char*)" at the beginning is required to tell gdb how to handle the result. char* basically means "string" in this case. Our object's address is a nightmareish glob of mess: "*(int)($ebp+20)" the * at the beginning tells us to dereference the pointer we're going to feed it. This is used because our data on the stack is actually a pointer to another pointer.

Next we have "(int)" which you may recognize as a typecast. we do this to tell gdb to interpret the data as an integer (as opposed to a floating point value, a string, a byte, etc). Without this, gdb doesn't know how to calculate the address because it doesn't know how much data you're dealing with.

Finally, the understandable "($ebp+20)". In gdb, registers are prefixed with dollar-signs to keep them separate from gdb keywords and in-program variables. The whole thing is in parenthesis so that the typecast above applies to both, not just $ebp. Without it, we'll generate an incorrect address and get a fun warning like Cannot access memory at address 0x2f737467.

If you somehow forget which method you're in, or the object does something ugly with message passing, you can find out what selector you're in with this: (gdb) x/s *(int)($ebp+12) which will then tell you something like this:
0x2fac : "setStuff:otherThings:andStr:"setStuff:otherThings:andStr: is our terribly-named example selector for this exercise :)

So there you have it. Actually, there I have it too, since I'll probably use this for reference in the future (I always forget nuggets like this when I need them). Now we can manipulate objects at our whim in any running Objective-C program without having a single line of source code. Pretty dangerous :)

Monday, August 6, 2007

Anti-aliases

Coming from a Linux background, I'm fairly comfortable with the idea of Symbolic Links. These are kind of like shortcuts on steroids; they transparently pose as files residing elsewhere, allowing all kinds of power (and problems).

Since OS X has some pretty strong Unix underpinnings, it came as no surprise to find that it supports Symbolic links out of the box. Unfortunately, the only way to create them is still with Terminal.app. No problem for me, being a keyboard cowboy, but for the average user it's a huge inconvenience.

Finder has a provision for making shortcuts, called aliases. This, unlike symbolic linking, is quite easy to use, and many non-programmer users use alias functionality. In fact, I even used aliases for a while, thinking they were simply symlinks renamed.

Then, along came a bug report to the Folder Movies Patch at kineme.net. Apparently, aliases were not symbolic links.

After a considerable amount of research, I discovered that aliases are Basically regular files. They report their length as zero bytes, and they store their data in a resource fork (oh how I loathe this concept...) To view the data, you can open a terminal, and type cat [alias file]/rsrc. You'll be greeted with some binary garbage, and some plain-text parts of the path to the real file.

So, how do we get a program to handle these peculiar files? Through some actions known as "Alias Resolution."

I won't bore you with all the exploration I did to come to the result, but here it is:


/* Multiple aliases in a path won't resolve here (we need to handle them one at a time)
so we need to prune off parts of the path recursively and try resolving those, then
rebuild the pruned off parts onto the resolved alias
*/
+ (NSString*) resolveAlias:(NSString *)filePath isFolder:(Boolean*)folder
{
unsigned char pathBuffer[4096];
FSRef fsRef;

if( FSPathMakeRef((const UInt8*)[filePath UTF8String], &fsRef,NO) == noErr )
{
Boolean isAlias = FALSE;
if( FSResolveAliasFile(&fsRef, TRUE, folder, &isAlias) == noErr && isAlias)
{
FSRefMakePath(&fsRef, pathBuffer, 4096);
return [NSString stringWithUTF8String:(const char*)pathBuffer];
}
}
else
{
//NSLog(@"FSPathMakeRef failed for %@\n",filePath);
// this fails when mutliple alises are in one path, so we prune and rebuild here
return [NSString stringWithFormat:@"%@/%@",
[self resolveAlias:[filePath stringByDeletingLastPathComponent] isFolder:folder],
[filePath lastPathComponent]
];
}
return nil;
}


This recursive method will take an NSString path, and resolve aliases as it goes. This means you can have an alias inside another alias, and they both get resolved correctly. It also takes a Boolean pointer to let you know if the ultimate target is a folder or not. It returns nil if there aren't any aliases in the path to resolve, otherwise it returns the resolved path, allowing you to access the target.

Wednesday, July 18, 2007

Second Nature

I've been writing Cocoa plugins for Quartz Composer (see kineme.net for more details) pretty consistently for the past month or so.

Such continual writing, especially in an already-existing application, has taught me many things, very quickly. It's quite fun; I now wish that I had had the opportunity (or probably just the motivation) to work in such an environment when I was learning C or C++ or even Basic. Immersion is such a powerful learning tool. Not to downplay the importance of theory though; without the theory I've learned from my first languages I would probably be dead in the water in Cocoa.

I'm no expert yet, nor will I be for quite a while (especially with Leopard coming so soon, with its new Xcode and tools), but I am way more comfortable with development, and, perhaps more importantly, with debugging.

So, what direction is there now for this blog? Anyone with determination can push themselves through the differences in Objective-C. I can't offer much more than anecdotal evidence for that.

Perhaps I should just make lots of demos to show how to do various things? Since I have zero readers, I guess this decision is ultimately up to me...

Tuesday, June 26, 2007

NSAutoReleasePool

NSAutoReleasePool is Memory Management object used in Cocoa. They act as a catch-all for allocations, cleaning up memory when objects are no longer needed.

Instead of sticking strictly to retain and release, these pools allow us one more memory management method: autorelease. This method puts our object in the most recently-created pool. When these pools get freed, all the objects in them get freed as well. Because of this behavior, it's common to put these pools around loops and inside functions that perform several allocations. It is common to create a pool right from the beginning in main(), as a catch-all for your entire application.

Additionally, Cocoa's Frameworks often require a pool to be available for things to work correctly. Without them, the program will probably still run, but it will generate Tons of warnings like this at runtime:


cwright@phendrana:~/projects/addr>./main.broken
2007-06-26 20:43:51.068 main.broken[3819] *** _NSAutoreleaseNoPool(): Object 0x1802000 of class NSCFDictionary autoreleased with no pool in place - just leaking


This is Cocoa's way of telling you that you need an autorelease pool in place to prevent leaks.

Using autorelease pools is quite simple: NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; sets up a pool. [pool release] cleans it up. They can be nested, so that a function can create one, and then a loop in that function can create its own as well. Nested pools get released automatically when their parent pool is released. This is probably very sloppy, but it appears to work.

Here's some sample code that shows this behavior, as well as usage of NSAutoReleasePool.


#import <Foundation/Foundation.h>

@interface OurObject: NSObject
-(void)dealloc;
@end

@implementation OurObject
-(void)dealloc
{
printf("Dealloc on OurObject\n");
[super dealloc];
}
@end

void createAPoolAndLeak()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OurObject *oo = [[OurObject alloc] init];

// add to this function's pool...
[oo autorelease];
// ... and forget to release the pool! *Gasp*
}

void createAPoolAndDontLeak()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OurObject *oo = [[OurObject alloc] init];

// add to this function's pool...
[oo autorelease];
// ... and release the pool!
[pool release];
}

int main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

printf("Creating a pool and not leaking...\n");
createAPoolAndDontLeak();
printf("Pool cleaned up.\n");
printf("Creating a leaky pool\n");
createAPoolAndLeak();
printf("Leaky pool created.\n");

printf("Releasing parent pool...\n");
[pool release];

printf("Pool is cleaned up...\n");
return 0;
}


Using these pools is disappointingly simple. They really don't require much work at all.

AddressBook

Ok, so I lied in my last post. I do have some GUI stuff in the works, but it's taking exceptionally long to screenshot the whole procedure. Sorry.

But, I do have one nugget of sample goodness for you: How to pull data out of the OS X AddressBook.

#import <Foundation/Foundation.h>
#import <AddressBook/ABAddressBook.h>
#import <AddressBook/ABMultiValue.h>

void printMultiValue(char *title,id prop, ABPerson *p)
{
int j,k;
ABMultiValue *multi = [p valueForProperty:prop];

if([multi count])
printf(" * %s:\n",title);

// sometimes we get NSDictionaries for values. These
// need to be handled differently (kABAddressProperty does this, for example)
if([[multi valueAtIndex:0] isKindOfClass:[NSDictionary class]] == YES)
{
for(k=0;k<[multi count];++k)
{
NSArray *keys, *values;
keys = [[multi valueAtIndex:k] allKeys];
values = [[multi valueAtIndex:k] allValues];

// get the dictionary name
printf(" * %s\n",
[[multi labelAtIndex:k] UTF8String]);

for(j=0;j<[keys count];++j)
{
printf(" * %s: %s\n",
[[keys objectAtIndex:j] UTF8String],
[[values objectAtIndex:j] UTF8String]);
}
}
}
else // normal handling
{
for(j=0;j<[multi count];++j)
{
printf(" * %s: %s\n",
//[[multi identifierAtIndex:j] UTF8String],
[[multi labelAtIndex:j] UTF8String],
[[multi valueAtIndex:j] UTF8String]);
}
}
}

int main()
{
int i;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ABAddressBook *book = [ABAddressBook sharedAddressBook];

NSArray *people = [book people];

printf(" * People count: %i\n",[people count]);

for(i = 0;i<[people count];++i)
{
printf(" * Person %i\n",i);
ABPerson *p = [people objectAtIndex:i];
printf(" * First Name : %s\n",[[p valueForProperty:kABFirstNameProperty] UTF8String]);
printf(" * Middle Name: %s\n",[[p valueForProperty:kABMiddleNameProperty] UTF8String]);
printf(" * Last Name : %s\n",[[p valueForProperty:kABLastNameProperty] UTF8String]);
printf(" * Company : %s\n",[[p valueForProperty:kABOrganizationProperty] UTF8String]);

printMultiValue("E-Mail",kABEmailProperty,p);
printMultiValue("Phone",kABPhoneProperty,p);
printMultiValue("Address",kABAddressProperty,p);

printf(" * Note : %s\n",[[p valueForProperty:kABNoteProperty] UTF8String]);
}

[pool release];
return 0;
}


That's a pretty loaded example. And to compile it from the command line: gcc main.m -o main -framework Cocoa -framework AddressBook. Here we use an AutoreleasePool, which I haven't talk about yet, as well as some NSString data to present some meaningful output to the user.

This program will dump out a ton of information found inside your addressbook. There are a few more fields inside, but this is probably enough to get you started. I'll have to go through and document more sometime.

Tuesday, June 19, 2007

Xcode Examples Coming Soon

Normally I work in command-line land because it's far more familiar to me, and easier to control. There's also naturally less code overhead, so you can focus on what's actually going on without all the extra fluff. That said, any useful application will need a useful user-interface to actually help someone accomplish work.

Xcode is Apple's IDE of choice for developing Cocoa applications. To compliment the 7 trillion screen-shot-laden Xcode blogs out there, I'll shortly be adding my own contribution to the mix.

That said, I intend to focus more on documenting how various GUI-related problems are solved using existing tools. It takes a considerable amount of work to make a well-polished user interface (probably another reason why I avoid GUI-land :), so I'll try to reveal as much polish as I can uncover.

Tomorrow, we'll begin our GUI adventures. Don't worry though, we'll still fall back to command-line for a while at least, to illustrate basic concepts and methods.

Monday, June 18, 2007

Retain and Release, and Object Creation

Objects in Objective-C maintain a counter to manage how many object point to the object in question. This counter modified by two methods, retain and release, and can be accessed directly by the retainCount method.

Each call to [object retain]; increments this counter, and each call to [object release]; decrements it. The retain/release counter starts at 1. When an object's count drop to 0, it deallocates itself. In Memory Management documentation, you'll find this behavior referred to as Reference Counting.

When an object deallocates itself, it uses its dealloc method. This method is comparable to a destructor in C++. Like C++, dealloc takes no arguments, and has no return value.

To create an object, you've probably noticed the [[object alloc] init]; sequence used. This uses two methods, alloc and init. alloc simply allocates memory. It is essentially the same as malloc() in C. init is used to initialize objects to a usable state. This is the job of a constructor in C++.

Writing our own init and dealloc methods requires a bit of work for things to work right. I'll present an example with both, and then explain the various parts and pieces.

#import <Foundation/Foundation.h>

@interface myObject: NSObject
{
@private
int count;
int refs;
}
-(id)init;
-(void)dealloc;
-(int)getCount;
-(void)incCount;
@end

@implementation myObject
-(id)init
{
self = [super init];
count = 0;
refs = 0;
printf("Running myObject's init method\n");
return self;
}

-(void)dealloc
{
printf("Running myObject's dealloc method\n");
[super dealloc];
}

-(int)getCount
{
return count;
}

-(void)incCount
{
++count;
}
@end

int main()
{
myObject *obj = [[myObject alloc] init];

printf("Object's count: %i\n",[obj getCount]);

[obj incCount];
[obj incCount];
[obj incCount];

printf("Object's count: %i\n",[obj getCount]);

[obj release];

return 0;
}


In this example, we have a simple class called myObject. This object implements a working init and dealloc, and little else.

First, an init method's declaration looks like this: -(id)init;. This means the return type is id, which is certainly not a standard C type. This type is similar to void* in C or C++. This basically means that we'll be returning a pointer to ourselves when the init method returns.

In the implementation of init we have some more magic. The first is self = [super init];. This line has two ideas; self and super. self is basically *this in C++. It's a reference to the object in question. So we're setting our object's reference to [super init]. This, unsurprisingly, uses super, another built-in variable that points to our class's parent class. Setting self to our object's parent's init method is required for proper inheritance.

Following all that stuff, init finishes with return self;. This returns a reference to our object so that the caller (main in this case) can access it.

In the dealloc method, we have a similar expression, [super dealloc];. This method does any necessary clean-up of our object using our class's parent's dealloc method. We are still responsible for any clean up we need to do ourselves (none in this example), but that's it.

Using init, dealloc, retain, and release allow us to start creating real complex classes, and do some basic memory management. There's still much more available in terms of memory management though, in the form of NSAutoReleasePools, but those are reserved for a future entry.

In case you were curious, the above program's output looks like this:
Running myObject's init method
Object's count: 0
Object's count: 3
Running myObject's dealloc method

Saturday, June 16, 2007

Object Antics

As with all Object-Oriented languages, Objective-C allows for some pretty handy trickery when it comes to objects, inheritance, and extensions. The terms used are fairly exclusive, but most of them have parallels.

In Cocoa Objects I briefly went over how to do basic inheritance. It is done by adding : InheritedObject on the @interface line, like this:

@interface myObject: NSObject


Objective-C does not allow multiple-inheritance. This means each object can only inherit from one object, and has only one super class, which we'll get into later.

Related to inheritance is an idea Objective-C refers to as Protocols. A protocol is comparable to a virtual class in C++, in that it defines what methods need to exist, but doesn't define how they work.

A protocol is defined very simply, as follows:
@protocol myProtocol
-(void) aMethod;
-(void) anotherMethod;
@end


For an object to adhere to this protocol, it must implement two methods, called aMethod and anotherMethod.

To indicate that an object adheres to a protocol, we use code like this:
@interface myClass: <myProtocol>


The stuff between the less-than and greater-than signs defines the protocol or protocols. If there are multiple protocols an object adheres to, they all appear between the brackets, in a comma-separated list, like this:
@interface myClass: <myProtocol, anotherProtocol>


Objects are meant to be dynamic in Objective-C. As such, NSObject provides a number of handy methods to help figure out what class an object inherits and what methods it uses.

#import <Foundation/Foundation.h>

@interface basicClass: NSObject
{
int basicInt;
}
@end

@interface mediumClass: basicClass
{
int mediumInt;
}
@end

@interface complexClass: mediumClass
{
int complexInt;
}
@end

@implementation basicClass
@end

@implementation mediumClass
@end

@implementation complexClass
@end

int main()
{
basicClass *bcObj = [[basicClass alloc] init];
mediumClass *mdObj = [[mediumClass alloc] init];
complexClass *cxObj = [[complexClass alloc] init];

if( [cxObj isKindOfClass: [mediumClass class]] == YES )
printf("cxObj is a kind of mediumClass\n");
else
printf("cxObj is not a kind of mediumClass\n");

if( [cxObj isKindOfClass: [basicClass class]] == YES )
printf("cxObj is a kind of basicClass\n");
else
printf("cxObj is note a kind of basicClass\n");

if( [bcObj isKindOfClass: [mediumClass class]] == YES )
printf("bcObj is a kind of mediumClass\n");
else
printf("bcObj is not a kind of mediumClass\n");

return 0;
}


As you can probably expect from this example, the output is this:
cxObj is a kind of mediumClass
cxObj is a kind of basicClass
bcObj is not a kind of mediumClass


We can use the isKindOfClass method to see if an object we get is of a particular kind. We can use the class method to get an object's class.

A related method is isMemberOfClass, which is used in exactly the same way as isKindOfClass. While isKindOfClass will return YES if any parent object is the specified class, isMemberOfClass will only return YES if the object in question's immediate parent (the super class) is the specified class. If we replace all all occurrences of isKindOfClass with isMemberOfClass in the example above, the output becomes:
cxObj is not a member of mediumClass
cxObj is note a member of basicClass
bcObj is not a member of mediumClass


Notice how complexClass is not a member of basicClass because basicClass is a grandparent object, not an immediate parent of complexClass.

There are a few other methods related to object methods, but they use selectors so I'll address those in a future entry. There are also methods we can use to determine if an object conforms to a given protocol. This will also be addressed later.

Up to this point, we've only dealt with @private for member variables, not methods. In fact, if you got adventurous and tried to mark some methods as private, you probably ran into some problems. This is because Objective-C has no syntax to create private member functions. The way around this is by using Categories. Categories are used to extend the functionality of a class by adding new methods. Simple usage looks like this:

#import 

@interface basicClass: NSObject
{
int basicInt;
}
@end

@implementation basicClass
@end

@interface basicClass (Extension)
-(void)extendedMethod;
@end

@implementation basicClass (Extension)
-(void)extendedMethod
{
printf("This method is in a category called \"Extension\"\n");
}
@end

int main()
{
basicClass *bcObj = [[basicClass alloc] init];

[bcObj extendedMethod];

return 0;
}


The (Extension) part defines the Category, which is called "Extension" in this case. The name can be pretty much anything though. However, each category name must be unique. Also, categories cannot add member variables, only methods.

Predictably, the output of the Category example above is:
This method is in a category called "Extension"


So, to create private member functions, all you need to do is add a Private category in the object's .m source file instead of the .h. This keeps the method inaccessible to callers outside of that .m file.

One last object trick available in Objective-C is the ability for a class to pose as its super class. This feature is aptly named "Posing." To have a class pose as another class, we use the poseAsClass method.
#import <Foundation/Foundation.h>

@interface basicClass: NSObject
{
int basicInt;
}
-(void) print;
@end

@implementation basicClass
-(void) print
{
printf("This is the basicClass method, uncooked.\n");
}
@end

@interface anotherClass: basicClass
@end

@implementation anotherClass
-(void) print
{
printf("This is anotherClass method.\n");
}
@end

int main()
{
basicClass *bcObj = [[basicClass alloc] init];
anotherClass *aObj = [[anotherClass alloc] init];

// after this, everything using basicClass will
// actually use anotherClass
[anotherClass poseAsClass: [basicClass class]];

basicClass *basicObject = [[basicClass alloc] init];

[bcObj print];
[aObj print];
[basicObject print];

return 0;
}


The output, demonstrating posing, looks like this:
This is the basicClass method, uncooked.
This is anotherClass method.
This is anotherClass method.


As you can see, the last two objects use the same print method, despite being different classes. This happens because of posing.

Friday, June 15, 2007

Cocoa Objects

Objects in Cocoa are very similar to objects in other languages such as C++ or Java. Their structure and syntax is very different though. While C++ and Java objects are essentially extensions (in syntax and organization) of the struct in C, Cocoa's objects are implemented in a completely different way, with a completely different syntax.

In C++, you'd create a class using some code kind of like this:

class myClass
{
private:
int anInteger;
float aFloat;
public:
void someMethod(float f);
int someOtherMethod(int i, float f);
};


and you'd have a class called myClass with 2 private member variables and 2 public member functions, or methods.

If you wanted, you could define the member functions inside the class declaration itself, or you could define them outside the class like this:

void myClass::someMethod(float f)
{
aFloat = f;
}


This would define the someMethod method of myClass. Because you can have different return types and argument types, C++ allows you to have different methods with the same name, as long as their types are different. This is a convention that is not allowed in Objective-C, as we shall shortly see.

In Objective-C, objects come in two parts, an interface and an implementation. These look completely weird to run-of-the-mill C/C++ Programmers, so brace yourself. This is an equivalent object in Objective-C.


@interface myObject
{
@private
int anInteger;
float aFloat;
}
-(void) someMethod:(float) f;
-(int) someOtherMethod:(int) i andFloat: (float) f;
@end


Right. So, we covered a lot right there. An object's interface is defined between @interface and @end. The name of the object is immediately after the @interface. Member variables are can be marked @public, @protected, or @private, with @protected being the default protection.

After the member variables, we declare the methods. The syntax here is pretty weird too. First, the method is declared either instance-scoped or class-scoped. Class-scoped is like static in C++. To declare a method as instance-scoped, use a minus sign: -. To declare it as class-scoped, use a plus sign: +.

Following the scope of the method, the return type is specified in parenthesis. Next comes the method name. If the method takes no parameters, we tack on a semicolon, and we're done. If it does, we tack on a colon, then specify the data type in parenthesis, followed by the variable name. If we have multiple parameters, it gets even more interesting.

-(int) someOtherMethod:(int) i andFloat: (float) f; uses two parameters. Instead of just having a list of arguments, Objective-C names them so that the user can keep track of what's going on. The andFloat part is doing just that. We don't strictly need to specify this part. We could simply use -(int) someOtherMethod:(int) i: (float) f; to make it look more like C. However, the names are pretty helpful, so I'd recommend using them.

As you've probably guessed by now, the @interface is similar the the class declaration. Thus, we're on to the @implementation.

@implementation myObject
-(void) someMethod:(float) f
{
aFloat = f;
}
-(int) someOtherMethod:(int) i andFloat: (float) f
{
anInteger = i;
aFloat = f;
}
@end


Not so surprisingly now, the @implementation defines the methods using almost the exact same syntax. It's pretty straightforward.

Typically the @interface goes in a .h header file. The @implementation goes in a .m source file. You can put them all in the same source file though if you want.

Inheritance is fairly common in Objective-C as well. In fact, it's practically essential for get to actually use our objects. Almost all the objects we create will extend NSObject. To do this, our interface line will look like this: @interface myObject: NSObject. Pretty close to C++'s method. It gets more complicated than this though, but that's for a future entry.

So now that we have basic objects at our disposal, it's time to talk about some rules regarding objects. First, objects cannot be statically allocated. If you try to, gcc will complain with an error like this: "error: statically allocated instance of Objective-C class." This is one of the reasons why we will almost always extend NSObject. The NSObject gives us a couple methods to dynamically create our objects. myObject *mo = [[myObject alloc] init]; is the typical way to allocate and initialize an object. The alloc method, as the name implies, allocates the necessary storage space, and init similarly initializes the object. This is in league with C++'s constructors.

Instead of delete, as we would use in C++ to free space used by an object, we use the release method, like this: [mo release];.

Before we continue, you've probably noticed that we call methods in a really different way. Instead of the expected myObject->method(args); syntax, we use [object method ... args]. To call a method with arguments from our object, it looks like this: [mo someMethod: 3.1415926];. You can probably guess how multiple parameters are handled, but here's another example just in case: [mo someOtherMethod: 42 andFloat: 1.234];.

So, to tie it all together into a working -- though useless -- example, here we go.

#import <Foundation/NSObject.h>
#import <stdio.h>

@interface myObject :NSObject
{
@private
int anInteger;
float aFloat;
}
-(void) someMethod:(float) f;
-(int) someOtherMethod:(int) i andFloat: (float) f;
@end

@implementation myObject
-(void) someMethod:(float) f
{
aFloat = f;
}
-(int) someOtherMethod:(int) i andFloat: (float) f
{
anInteger = i;
aFloat = f;
}
@end

int main(void)
{
myObject *mo = [[myObject alloc] init];

[mo someMethod: 3.1415926];
[mo someOtherMethod: 42 andFloat: 1.234];

[mo release];
return 0;
}


When compiling, be sure to use -framework Cocoa or else you'll get errors that are hard to understand. Like the following:

/usr/bin/ld: Undefined symbols:
.objc_class_name_NSObject
_objc_msgSend
collect2: ld returned 1 exit status


As an added bonus, you've been exposed to #import. You can safely assume that it's basically the same as #include -- in fact, you can often use them interchangeably -- except that #import makes sure to only include the file once without the #ifndef HEADER_H / #define HEADER_H / #endif stuff that litters the top and bottom C header files.

There you have it, the basics of Objective-C objects, and simple usage of Cocoa's framework.

Thursday, June 14, 2007

A Crash Course in Cocoa

I've been a C/C++ programmer for years. While it wasn't my first programming language, I have certainly used it the most and spent the most time with it. To further complicate matters, many of the other languages I've worked with over the past several years that weren't C or C++ were at least strongly based on C's syntax and structure. With all of this experience and momentum, it is personally difficult to change my ways and move on to new and different things.

But all is not lost! While traveling blindly on this path from C to Cocoa, I intend to document my findings, annoyances, and cool tricks for posterity. May your journey be easier where trails have already been blazed.


Cocoa is a superset of the C programming language. While it has some similarities with C++, it uses none of its conventions, and certainly none of its syntax. There are parallels, however. It's simply a matter of finding them.

The simplest part of the language, its datatypes, are textbook C types. You can use this program to find the sizes of various types:

main.m:

#include <stdio.h>

#define pso(type) \
printf("sizeof "#type": %4i bits\n",sizeof(type)*8);

int main(void)
{
pso(unsigned char);
pso( signed char);
pso(unsigned short int);
pso(short int);
pso(unsigned int);
pso(int);
pso(unsigned long);
pso(long);
pso(float);
pso(double);
pso(long double);
pso(void*);
return 0;
}


Compiled using gcc main.m -o main. As you can see, the code is perfectly valid C, minus the macro hackery for simplicity. POSIX is even thrown in for good measure. To compile the program for 64-bit mode, use this: gcc main.m -o main64 -m64. The -m64 part tells GCC to use 64-bit instructions and addressing. Currently, this only works for command-line applications under OS X 10.4, but for 10.5 it should work for GUI applications as well.

The output of this program is also comforting. For 32-bit mode, the output looks something like this:

sizeof unsigned char:       8 bits
sizeof signed char: 8 bits
sizeof unsigned short int: 16 bits
sizeof short int: 16 bits
sizeof unsigned int: 32 bits
sizeof int: 32 bits
sizeof unsigned long: 32 bits
sizeof long: 32 bits
sizeof float: 32 bits
sizeof double: 64 bits
sizeof long double: 128 bits
sizeof void*: 32 bits


The output for 64-bit builds looks like this:
sizeof unsigned char:       8 bits
sizeof signed char: 8 bits
sizeof unsigned short int: 16 bits
sizeof short int: 16 bits
sizeof unsigned int: 32 bits
sizeof int: 32 bits
sizeof unsigned long: 64 bits
sizeof long: 64 bits
sizeof float: 32 bits
sizeof double: 64 bits
sizeof long double: 128 bits
sizeof void*: 64 bits


The only differences are the length of long and void*. The latter means that pointers are 64 bits instead of 32, giving us address space far beyond the 4GB limit. It also means that when doing pointer arithmetic, using int types will result in errors when the top 32 bits get truncated.

So from the above, we've seen that Cocoa can look and act exactly like C. The data types are the same, as is the syntax. The ride only gets bumpier from here though. With the introduction of Objects, we'll see both data types and syntax get turned upside-down.

Categories