views:

3193

answers:

8

Objective-C is getting wider use due to its use by Apple for Mac OS X and iPhone development. What are some of your favourite "hidden" features of the Objective-C language?

  • One feature per answer.
  • Give an example and short description of the feature, not just a link to documentation.
  • Label the feature using a title as the first line.
+14  A: 

Posing

Objective-C permits a class to entirely replace another class within an application. The replacing class is said to "pose as" the target class. All messages sent to the target class are then instead received by the posing class. There are some restrictions on which classes can pose:

  • A class may only pose as one of its direct or indirect superclasses
  • The posing class must not define any new instance variables which are absent from the target class (though it may define or override methods).
  • No messages must have been sent to the target class prior to the posing.

Posing, similarly to categories, allows globally augmenting existing classes. Posing permits two features absent from categories:

  • A posing class can call overridden methods through super, thus incorporating the implementation of the target class.
  • A posing class can override methods defined in categories.

An example:

@interface CustomNSApplication : NSApplication
@end

@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
     // do something with menu
}
@end

class_poseAs ([CustomNSApplication class], [NSApplication class]);

This intercepts every invocation of setMainMenu to NSApplication.

splattne
Class_poseAs is deprecated starting in 10.5. The replacement is doing the same on a method by method basis, which is now explicitly supported in the runtime.
Ken
Oops, forgot to link the [docs](http://developer.apple.com/releasenotes/Cocoa/RN-ObjectiveC/index.html).
Ken
+8  A: 
#include <Foundation/Debug.h>

Lots of tools for trying to track down memory leaks, premature deallocs, and more in that header file.

schwa
That's Cocoa specific (maybe OpenSTEP too?) rather than a language feature, though since no-one uses ObjC except with Cocoa I guess it doesn't make a lot of difference
Mark Baker
+6  A: 

Object Forwarding/Method Missing

When an object is sent a message for which it has no method, the runtime system gives it another chance to handle the call before giving up. If the object supports a -forward:: method, the runtime calls this method, passing it information about the unhandled call. The return value from the forwarded call is propagated back to the original caller of the method.

-(retval_t)forward:(SEL)sel :(arglist_t)args {
  if ([myDelegate respondsTo:sel])
 return [myDelegate performv:sel :args]
 else
 return [super forward:sel :args];
 }

Content from Objective-C Pocket Reference

This is very powerful and is used heavily in the Ruby community for the various DSLs and rails, etc. Originated in Smalltalk which influenced both Objective-C and Ruby.

methym
+13  A: 

Method Swizzling

Basically, at runtime you can swap out one implementation of a method with another.

Here is a an explanation with code.

One clever use case is for lazy loading of a shared resource: usually you would implement a sharedFoo method by acquiring a lock, creating the foo if needed, getting its address, releasing the lock, then returning the foo. This ensures that the foo is only created once, but every subsequent access wastes time with a lock that isn't needed any more.

With method swizzling, you can do the same as before, except once the foo has been created, use swizzling to swap out the initial implementation of sharedFoo with a second one that does no checks and simply returns the foo that we now know has been created!

Of course, method swizzling can get you into trouble, and there may be situations where the above example is a bad idea, but hey... that's why it's a hidden feature.

benzado
+4  A: 

Objective-C Runtime Reference

It's easy to forget that the syntactic sugar of Objective-C is converted to normal C function calls that are the Object-C Runtime. It's likely that you will never need to actually delve into and use anything in the runtime. That is why I would consider this a 'hidden feature'.

Let me give a way one might use the runtime system.

Let's say that someone is designing an external framework API that will be used by third parties. And that someone designs a class in the framework that abstractly represents a packet of data, we'll call it MLAbstractDataPacket. Now it's up to the application who is linking in the framework to subclass MLAbstractDataPacket and define the subclass data packets. Every subclass must override the method +(BOOL)isMyKindOfDataPacket:(NSData *)data.

With that information in mind...

It would be nice if MLAbstractDataPacket provided a convenience method that returned the correct initialized class for a packet of data that comes in the form +(id)initWithDataPacket:(NSData *)data.

There's only one problem here. The superclass doesn't know about any of its subclasses. So here you could use the runtime method objc_getClassList() along with objc_getSuperclass() to find the classes that are subclasses of MLAbstractDataPacket. Once you have a list of subclasses you can then try +isMyKindOfDataPacket: on each until one is found or not found.

The reference information about this can be found at http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html.

Michael Ledford
+8  A: 

Categories

Using Categories, you can add methods to built-in classes without subclassing. Full reference.

It's nice to add convenience methods to commonly used classes, such as NSString or NSData.

Marco
Great tip, but not quite hidden… :)
Jonathan Sterling
+1  A: 

I like the verbose method naming like [myArray writeToFile:myPath atomically:YES], where every argument has a label.

Kris
How is that hidden?... :)
Psionides
@Psionides: It's pretty obvious to people that actually use the language I agree, but most people coming from some other language most people seem to miss this simple fact. at least the folks I've spoken with.
Kris
You can't miss it! Not if you actually want to pass messages!
Casebash
+6  A: 

ISA Switching

Need to override all of an object's behaviors? You can actually change the class of an active object with a single line of code:

obj->isa = [NewClass class];

This only changes the class that receives method calls for that object; it doesn't change the object's layout in memory. Thus, this is only really useful when you have a set of classes with the same ivars (or one with a subset of the others') and you want to switch between them.

One piece of code I've written uses this for lazy loading: it allocates an object of class A, fills a couple critical ivars (in this case, mainly a record number) and switches the isa pointer to point to LazyA. When any method other than a very small set like release and retain is called, LazyA loads all the data from disk, finishes filling in the ivars, switches the isa pointer back to A, and forwards the call to the real class.

Brent Royal-Gordon
My god, I never thought of that. I need to test this, because it's brilliant. I wonder whether there are any nasty side-effects?
Jonathan Sterling