Reading — step 1 of 5
Learn
Objective-C is dynamically typed — every method dispatch goes through the runtime. This enables features no static language has: method swizzling, class extension at runtime, KVO, dynamic class creation.
The runtime API
Includes <objc/runtime.h>:
#import <objc/runtime.h>
Class cls = [NSString class];
Method m = class_getInstanceMethod(cls, @selector(uppercaseString));
IMP impl = method_getImplementation(m);
%% impl is the actual C function pointer
Method swizzling
Replace a method's implementation at runtime — used by debuggers, mocking libraries, KVO:
@implementation NSString (Logging)
+ (void)load {
Method original = class_getInstanceMethod([NSString class], @selector(length));
Method swizzled = class_getInstanceMethod([NSString class], @selector(loggedLength));
method_exchangeImplementations(original, swizzled);
}
- (NSUInteger)loggedLength {
NSUInteger len = [self loggedLength]; %% calls the ORIGINAL after swizzle
NSLog(@"length called: %lu", len);
return len;
}
@end
Now EVERY call to [someString length] goes through your wrapper. Powerful and dangerous.
Dynamic class creation
Class DynamicClass = objc_allocateClassPair([NSObject class], "DynamicClass", 0);
class_addMethod(DynamicClass, @selector(greeting),
(IMP)greetingIMP, "@@:");
objc_registerClassPair(DynamicClass);
id instance = [[DynamicClass alloc] init];
[instance performSelector:@selector(greeting)];
Used by ORMs, KVO, mocking frameworks.
Method introspection
%% List all methods of a class
unsigned int count;
Method *methods = class_copyMethodList([NSString class], &count);
for (unsigned int i = 0; i < count; i++) {
SEL sel = method_getName(methods[i]);
NSLog(@"method: %s", sel_getName(sel));
}
free(methods);
Useful for serialization, dependency injection, debugging.
Associated objects
Attach extra data to existing instances without subclassing:
static char kAssocKey;
objc_setAssociatedObject(someObject, &kAssocKey, @"extra", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
NSString *extra = objc_getAssociatedObject(someObject, &kAssocKey);
This is how you add stored properties via categories — categories normally can't add ivars, but associated objects work around it.
NSInvocation
For calls with more args than performSelector supports, or for method forwarding:
NSMethodSignature *sig = [target methodSignatureForSelector:@selector(method:arg2:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
[inv setTarget:target];
[inv setSelector:@selector(method:arg2:)];
[inv setArgument:&arg1 atIndex:2]; %% 0=self, 1=_cmd, 2+=user args
[inv setArgument:&arg2 atIndex:3];
[inv invoke];
NSString *result;
[inv getReturnValue:&result];
Verbose but powerful — used in NSProxy, KVO observation forwarding.
Why this matters
Objective-C's dynamism makes:
- KVO (Key-Value Observing) — observe property changes without writing notification code
- Cocoa Bindings — auto-sync UI to model
- Core Data — automatic ORM with NSManagedObject
- Swift's @objc bridging — Swift can call Objective-C dynamic methods
Understanding the runtime is essential for serious ObjC work — and gives you appreciation for what Swift gives up (and gains) by being statically typed.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…