- Blocks as Methods
- Protocol Construction
- Property Reflection
Protocol Construction
In older versions of Objective-C, protocols were treated as just names at runtime. By contrast, current versions give protocols fairly rich runtime introspection capabilities.
The ability to construct protocols at runtime is completely useless to most programmers; therefore, it was omitted when the modern runtime removed the ability to manipulate the various runtime structures directly. It was assumed that only compilers would need to construct protocols. Unfortunately, one category of software does want to construct protocols: language bridges.
For example, PyObjC needs to be able to create protocols for classes implemented in Python so that other code can introspect them. These programs are almost compilers; they generate the same sorts of structures (classes, protocols, and so on) that compilers generate, but they need to do it at runtime. When a static compiler generates these structures, it includes an ABI version in the final executable so that the runtime can update the structures to a newer representation if required. In contrast, something generating them at runtime would just cause problems if it tried to generate a newer representation.
With the latest version of the runtime, for example, you can create a protocol that defines a +dealloc method for freeing classes created at runtime:
Protocol *p = objc_allocateProtocol("RuntimeAllocated"); protocol_addMethodDescription(p, @selector(dealloc), "v@:", YES, NO); objc_registerProtocol(p);
The protocol_addMethodDescription() function takes the selector and a type encoding to describe the methods, and two flags indicating whether the method is required (yes) and whether it's an instance method (no).
As with classes, you must register the new protocol with the runtime after creating it. This requirement allows the runtime to reject duplicate protocols. Unfortunately, these functions are a little bit buggy.
If you call objc_allocateProtocol() and then objc_registerProtocol(), the next time you try to call objc_allocateProtocol() with the same protocol name, it will return NULL, as you'd expect; you can't create two protocols with the same name. However, if you call objc_allocateProtocol() twice (perhaps in two threads) with the same argument, it will return two protocols. When you try to register them, the registration will succeed in both cases, and the second call will replace the first. This is almost certainly not the intended behavior.
This result is especially unfortunate, because it can't easily be worked around in user code. If the first protocol to be registered with a given name were always used, it would be easy to check, but you can't test whether another thread has called objc_allocateProtocol() with the same name before you register. The only thing you can do is wrap your protocol-creation code with a mutex and hope that no other libraries are trying to create protocols with the same name as yours.