Fun with the ObjectiveC Runtime
Thursday, November 3, 11
About
1818 Library Street | 5th Floor | Reston, VA 20190 main: 571-346-7544 | www.aboutobjects.com
iOS Developer Training • Enterprise iOS Development
Jonathan Lehr Founder, CEO •Began teaching and
developing in Objective-C in 1991.
•Once wrote a couple
books on (*cough*) Java development.
Thursday, November 3, 11
About
1818 Library Street | 5th Floor | Reston, VA 20190 main: 571-346-7544 | www.aboutobjects.com
iOS Developer Training • Enterprise iOS Development
Fun With the Objective-C Runtime
Part 1
Introduction
www.aboutobjects.com Thursday, November 3, 11
Documentation
• The Objective-C Programming Language • Objective-C Runtime Reference • Objective-C Runtime Programming Guide
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
4
Objective-C Runtime
• You normally interact with the runtime indirectly.
• Still pretty interesting though. • Example: message forwarding.
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
5
A Barking Cat • NSObject provides message forwarding API - (id)forwardingTargetForSelector:(SEL)aSelector; - (void)forwardInvocation:(NSInvocation *)anInvocation; - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
• Our Cat class overrides
forwardingTargetForSelector ‣
Allows instances of Cat to forward messages they don't respond to themselves.
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
6
Cat.h
#import "Pet.h" @interface Cat : Pet @property (nonatomic, retain) Pet *colleague; @end
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
7
Cat.m #import "Cat.h" @implementation Cat @synthesize colleague = _colleague; - (void)dealloc { [_colleague release]; [super dealloc]; } // Overrides inherited implementation... // - (id)forwardingTargetForSelector:(SEL)aSelector { NSLog(@"Forwarding message '%@' to instance of %@", NSStringFromSelector(aSelector), [_colleague class]); // Makes the cat's colleague the target for any // message the cat doesn't respond to. // return _colleague; } © Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
8
Dog.m
#import "Dog.h" @implementation Dog - (void)bark { printf("Woof! Woof!\n"); } @end
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
9
main.m int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Dog *rover = [[Dog alloc] initWithName:@"Rover"]; Cat *kitty = [[Cat alloc] initWithName:@"Kitty"]; [kitty display]; // If we don't set this, the app will crash on the following line. [kitty setColleague:rover]; // Note: using introspection to avoid compiler warning. [kitty performSelector:@selector(bark)]; [pool release]; return 0; }
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
10
Fun With the Objective-C Runtime
Part 2
The Runtime www.aboutobjects.com Thursday, November 3, 11
Runtime Library • C API • A few examples: // Sending a message. // Sending a message to super.
objc_msgSend objc_msgSendSuper
method_getName // Obtaining info about a method. method_getNumberOfArguments object_getInstanceVariable // Getting and setting ivars. object_setInstanceVariable property_getName // Obtaining info about a property. property_getAttributes class_copyMethodList class_replaceMethod
// Obtaining a class's method list. // Swizzling a method.
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
12
ExampleRunner • Like a super-simplistic test harness • Looks for classes whose name ends with Examples
• Creates an instance of each matching class ‣
Looks for methods whose names begin with example
‣
Invokes each matching method
‣
Swallows any thrown exceptions © Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
13
main.m
import #import "message_send.h" int main (int argc, const char * argv[]) { @autoreleasepool { sendMessages(); } return 0; }
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
14
sendMessages {
void sendMessages(void) // Get a count of all the registered classes int count = objc_getClassList(NULL, 0); if (count == 0) return; // Allocate and populate an array of classes. Class *classes = calloc(count, sizeof(Class)); objc_getClassList(classes, count); for (int i = 0; i < count; i++) { Class currClass = classes[i]; NSString *className = NSStringFromClass(currClass); // If the class name ends with "Examples"... if ([className hasSuffix:@"Examples"]) { printf("\nRunning examples for class %s\n", [className UTF8String]);
} }
}
// ...dynamically dispatch the class's instance methods. sendMessagesForClass(currClass);
free(classes);
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
15
sendMessageForClass {
void sendMessagesForClass(Class class) // Create an instance to send messages to. id instance = [[class alloc] init]; // Get a list of methods implemented by the class. unsigned int count; Method *methods = class_copyMethodList(class, &count); // Loop through the method list. for (int i = 0; i < count; i++) { Method currMethod = methods[i]; SEL selector = method_getName(currMethod); NSString *name = NSStringFromSelector(selector);
}
}
// Dispatch only to messages that have a matching prefix. if ([name hasPrefix:@"example"]) { sendMessageForSelector(instance, selector); }
[instance release]; free(methods);
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
16
sendMessageForSelector void sendMessageForSelector(id target, SEL selector) { NSString *name = NSStringFromSelector(selector); printf("\n*** %s ***\n", [name UTF8String]); // Catch any thrown exceptions so we can continue running // the other methods if an exception occurs. @try { // Dispatch the message. objc_msgSend(target, selector); } @catch (NSException *exception) { NSLog(@"%@: %@", [exception class], [exception reason]); } }
© Copyright 2008–2010, About Objects, Inc. All rights reserved worldwide.
Thursday, November 3, 11
17