I’ve been tinkering with Objective C for a while now and its a rather interesting beast. You can see some of the underlying concepts and how it diverged from C and Smalltalk. I do sometimes wonder what Steve was thinking when he choose Objective C all those years ago at NeXT instead of C++ which was emerging at the time.
But there have been a few areas which have caught me out, usually due to the lackluster documentation on the part of Apple; I am used to the rather extensive MSDN being the proveour of all knowledge and the downright bizzarre ways you have to go about implementing things.
Calling threads from Objective C is actually quite straightforward, just a simple call to NSThread usually does the job:
[NSThread detachNewThreadSelector:@selector(method:) toTarget:[MethodClass class] withObject:nil];
With MethodClass being the name of the Class and Method being the name of a Method (who would have guessed…) within said class. The fun begins when you want to pass variables. In .Net this is easy’ish as you just pass them in …as arguments using a delegate, its a bit more annoying in Objective-C.
Notice the withObject:nil at the end, you can replace nil with a parameter however you can only have 1, so the best way is to pass in a NSDictionary Object filled with all relevant arguments.
If you have used different threads you have most likely got caught out by AutoRelease Pools, or to the point, the lack of the autorelease pool giving rise to an error message like:
…of class NSCFString autoreleased with no pool in place – just leaking
New threads don’t have their own autorelease pool so classes that use autoreleased objects begin to leak. You have to create one instead.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Your code here
Threads Terminating too soon
You may have noticed a trend here, finally with threads, sometimes if you are handling async requests the thread may exit preemptively culling any request. To stop this from happening, we can use the default runloop to keep the thread alive until the async request has completed.
// Trigger async request
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
The variable finished should be set to YES when the async request has completed.
Objective-C Message Passing
The way that Objective-C interacts with Objects comes from its influences from SmallTalk. Instead of C++ where the object is referenced ala Scala approach, and the method calls are resolved at compile time. Objective-C takes the dynamic approach where calls to objects are made during runtime. This does introduce a small ‘lag’ during the initial reference as the links are checked but are cached and are at near C++ speeds afterwards.
My issue with this dynamic referencing is that the runtime does not always pick up on this. If an object doesn’t exist or a method within a function does not exist it just returns an error roughly equivalent to ‘not found’ however sometimes the runtime just ignores these and carries on its merry way.
A good example of this would be the following code
NSMutableDictionary *exampleDictionary = nil;
[exampleDictionary setObject:@"test1" forKey:@"test1"];
exampleDictionary = [[NSMutableDictionary dictionary] retain];
[exampleDictionary setObject:@"test2" forKey:@"test2"];
NSLog(@”The number of keys is: %d”, [exampleDictionary count]);
The number of elements you would expect at quick glance would be 2, seeing as we call setObject:forKey: twice. However it will only be 1 as we only set one element after the dictionary has been initalised. This can be an issue as the runtime does not throw an error when we set the first element, and the compiler does not warn us.
…Don’t worry, there will be plenty more Objective C issues where they came from