To summarize, the following are the key elements of Objective-C object messaging:
- Message: A name (the selector) and a set of parameters sent to an object/class.
- Method: An Objective-C class or instance method that has a specific declaration comprised of a name, input parameters, a return value, and the method signature (the data type(s) for the input parameters and return value).
- Method binding: The process of taking a message sent to a particular receiver and finding and executing the appropriate method. The Objective-C runtime performs dynamic binding of messages to method calls.
The Objective-C runtime uses selectors to retrieve the correct method implementation for a target object/class.
selector type is a special objective type that represents a unique identifier that replaces a selector value when the source is compiled.
Given that sumAddend1:addend2: method exist in class Calculator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Calculator * myCalc = [[Calculator alloc] init]; NSNumber *addend1 = [NSNumber numberWithInteger:25]; NSNumber *addend2 = [NSNumber numberWithInteger:10]; id sum1; NSLog(@"1"); //All methods with the same selector value have the same SEL identifier SEL selector1 = @selector(sumAddend1:addend2:); NSLog(@"2"); sum1 = [myCalc performSelector:selector1 withObject:addend1 withObject:addend2]; NSLog(@"3"); NSLog(@"Sum of %@ + %@ = %@", addend1, addend2, sum1); |
Result:
2015-09-25 08:39:25.616 RunTime1[3929:383317] Hello, World!
2015-09-25 08:39:25.617 RunTime1[3929:383317] 1
2015-09-25 08:39:25.617 RunTime1[3929:383317] 2
2015-09-25 08:39:25.618 RunTime1[3929:383317] sumAddend1:addend2: with 25 10
2015-09-25 08:39:25.618 RunTime1[3929:383317] 3
2015-09-25 08:39:25.618 RunTime1[3929:383317] Sum of 25 + 10 = 35
But what if we have a method signature that does not exist, say sumAddend1:addend25:?
You will get a SIGABRT error. Your code will also exit right at
1 2 |
sum1 = [myCalc performSelector:selector1 withObject:addend1 withObject:addend2]; |
with a Thread 1:signal SIGABRT error.
The rest of your code will not be executed.
result:
2015-09-25 08:18:11.524 RunTime1[3897:378030] Hello, World!
2015-09-25 08:18:11.525 RunTime1[3897:378030] 1
2015-09-25 08:18:11.525 RunTime1[3897:378030] 2
2015-09-25 08:18:11.525 RunTime1[3897:378030] -[Calculator sumAddend1:addend25:]: unrecognized selector sent to instance 0x100101af0
2015-09-25 08:18:11.617 RunTime1[3897:378030] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[Calculator sumAddend1:addend25:]: unrecognized selector sent to instance 0x100101af0’
*** First throw call stack:
(
0 CoreFoundation 0x00007fff8aa77bd2 __exceptionPreprocess + 178
1 libobjc.A.dylib 0x00007fff86f36dd4 objc_exception_throw + 48
2 CoreFoundation 0x00007fff8aae10ed -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00007fff8a9e83d1 ___forwarding___ + 1009
4 CoreFoundation 0x00007fff8a9e7f58 _CF_forwarding_prep_0 + 120
5 RunTime1 0x0000000100000afa main + 282
6 libdyld.dylib 0x00007fff980215ad start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
In order to avoid this, use try/catch/finally so that it will simply throw an exception and keep your code moving.
Also, notice because there was an error at performSelector due to a non-existent method signature, the rest of the try code block was not executed from NSLog 3 and on.
We go straight to the exception/finally code blocks, then continue on to the rest of the code after the try/catch/finally block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
id sum1; @try { NSLog(@"1"); //All methods with the same selector value have the same SEL identifier SEL selector1 = @selector(sumAddend1:addend25:); NSLog(@"2"); sum1 = [myCalc performSelector:selector1 withObject:addend1 withObject:addend2]; NSLog(@"3"); NSLog(@"Sum of %@ + %@ = %@", addend1, addend2, sum1); } @catch (NSException * exception) { NSLog(@"4 - after performSelector fails, jumps straight to here"); NSLog(@"Exception!!! %@", [exception description]); } @finally { NSLog(@"5"); NSLog(@"finally!"); } NSLog(@"6"); NSLog(@"the rest"); |
2015-09-25 08:44:45.987 RunTime1[3952:385189] Hello, World!
2015-09-25 08:44:45.988 RunTime1[3952:385189] 1
2015-09-25 08:44:48.275 RunTime1[3952:385189] 2
2015-09-25 08:44:48.276 RunTime1[3952:385189] -[Calculator sumAddend1:addend25:]: unrecognized selector sent to instance 0x100100c60
2015-09-25 08:44:48.278 RunTime1[3952:385189] 4 – after performSelector fails, jumps straight to here
2015-09-25 08:44:48.278 RunTime1[3952:385189] Exception!!! -[Calculator sumAddend1:addend25:]: unrecognized selector sent to instance 0x100100c60
2015-09-25 08:44:48.278 RunTime1[3952:385189] 5
2015-09-25 08:44:48.279 RunTime1[3952:385189] finally!
2015-09-25 08:44:48.279 RunTime1[3952:385189] 6
2015-09-25 08:44:48.279 RunTime1[3952:385189] the rest