Objective-C : Documentation : Advanced Topics


Classes and Messages

Dynamic Binding

How Messaging Works

objcMessageSend(..)

RespondsTo:

The - respondsTo: method is usefull for testing at run-time whether an object or class implements a given method.

Message Forwarding

If a message is sent to an object which does not contain a cooresponding method, a - forward:: message is sent to that object. This message contains the selector of the method name and the arguments sent with the message.

	- forward: (SEL)aSelector :(arglist_t)arguments;

The Object class implements - forward:: . Overriding this method in your own classes can be usefull for sending messages that one object doesn't understand to another that does. (not unlike multiple inheritance)

For example:

	- forward: (SEL)aSelector :(arglist_t)arguments
	{
	      return [otherObject performv:aSelector :arguments];
	}
Note: In NeXT Objective-C the arglist_t structure is named marg_list.

Posing

Describe `poseAs:'. Changing Behavior of Inherited Methods. Substituting a your new class for some old class. You can use this to override methods that have already been defined in the implementation of the old class.

Use subclassing to override method behavior in new classes you write. Use posing to override method behavior in preexisting subclasses of the posed class.

Dynamic Class Loading

The possibility to load class definitions and method definitions (which extend a class) at run time.

Dynamic Method Loading

Catagories

Categories. You can use this feature to add new methods to a class, but not to change methods that have already been defined in the class implementation. You can't add new instance variables (although I should include a footnote that shows the hack for getting around this).

Catagories are generally only usefull when adding methods to a class in a library that is already compiled(one that you don't have source code access to).

Protocols

Protocols are an addition to Objective-C that allows you to organize related methods into groups that form high-level behaviors. Protocols are currently available in NeXTSTEP (since 3.0) and GCC (since 2.4).

How Protocols are Used

Protocols provide an easy means of declaring the same set of methods in multiple class(or catagory) interfaces. They also offer a conveint way to check at run time whether or not a given object implements a set of methods(using the - conformsTo: method), instead of checking each method individually(using the - respondsTo: message).

Type Checking

Protocols allow you to get type-checking features without sacrificing dynamic binding. You can say "any object which implements the messages in Protocol Foo is OK for this use", which is usually what you want - you're constraining the functionality, not the implementation or the inheritance.

Reuse and APIs

Protocols give library builders a tool to identify sets of standard protocols, independent of the class hierarchy. Protocols provide language support for the reuse of design, whereas classes support the reuse of code. Well designed protocols can help users of an application framework when learning or designing new classes.

An Example

Here is a simple protocol definition for archiving(activativing/passivating) objects:

    @protocol Archiving
    -read: (Stream *) stream;
    -write: (Stream *) stream;
    @end
Once defined, protocols can be referenced in a class interface as follows:

    @interface MyClass: Object <Archiving>    
Unlike copying methods to/from other class interfaces, any incompatible change made to the protocol will immediately be recognized by the compiler (the next time the class is compiled). Protocols also provide better type checking without compromising the flexibility of untyped, dynamically bound objects.

    MyClass *obj1 = [MyClass new];

    // OK: obj1 conforms to the Archiving protocol.
    id <Archiving>obj2 = obj1;

    // Error: obj1 does not conform to the TargetAction protocol.
    id <TargetAction>obj3 = obj1;
Resolving Name Conflicts

Another use of protocols is that you can declare an Id to conform to some protocol in order to help the compiler to resolve method name conflicts:

 
    @interface Foo: Object
    -(int) type;
    @end

    @protocol Bar
    -(const char *) type;
    @end
 

    -blah1: d
    {
        id t = [d someMethod];
        do_something_with ([t type]);
    }

    -blah2: d
    {
        id <Bar >t = [d someMethod];
        do_something_with ([t type]);
    }
In this example, there are two kinds of the `-type' method. In the method `-blah1:', the compiler doesn't know what return type to expect from `[t type]', since it has seen both declarations of `-type'. In method `-blah2:', it knows that `t' conforms to the `Bar' protocol and thus that `t' implements the `-type' method returning a `const char *'.