From your code sample it looks like you are expecting a selector for a method which takes an NSText *
and return an NSString *
. So from your linked answer you can determine that the implementation of this method has the function type:
NSString *(*)(ID, SEL, NSText *)
Here ID
may be replaced by the type of callback
, and NSText *
can be replaced by the actual type of textCell.textField.text
if our guess is wring.
Again from your linked answer, you can obtain the implementation and call it using:
NSString *(*implementation)(ID, SEL, NSText *)
= (void *)[callback methodForSelector: performSelector:validatorSel];
NSString *message = implementation(callback, validatorSel, textCell.textField.text);
As @RobNapier correctly points out this is only safe under ARC if the selector does not return a retained value, i.e. for normal[*] selectors if it is a member of the init, copy, or new method families. Now you are very unlikely to be passed an init family method for validatorSel
as that would require callback
to be a reference to an alloc
'ed but not init
'ed object, so we can ignore that one for now[#]. To test for the other two families you can use code along the lines of:
NSString *message; // for the return value of the selector
NSString *selName = NSStringFromSelector(validatorSel); // get string name of selector
if ([selName hasPrefix:@"new"] // starts with new,
|| [selName hasPrefix:@"copy"] // or copy,
|| [selName rangeOfString:@"Copy"].location != NSNotFound) // or contains "Copy"
{
// need to handle returning a retained object
...
}
else
{
// normal case
NSString *(*implementation)(ID, SEL, NSText *)
= (void *)[callback methodForSelector: performSelector:validatorSel];
message = implementation(callback, validatorSel, textCell.textField.text);
}
Which just leaves how to handle the return value correctly under ARC for copy and new family methods...
Handling copy and new family methods
ARC knows that a method, or function, returns a retained object by an attribute being placed on the method/function type. The naming convention is just the language's way of inferring the attribute if it is not present, it can be manually specified using the NS_RETURNS_RETAINED
macro on a method/function declaration. So the missing code above is just:
{
// need to handle returning a retained object
NSString *(*implementation)(ID, SEL, NSText *) NS_RETURNS_RETAINED
= (void *)[callback methodForSelector: performSelector:validatorSel];
message = implementation(callback, validatorSel, textCell.textField.text);
}
The modified type for implementation
tells ARC that it will return a retained object and ARC will handle the call the same way it does for known copy or new family methods.
HTH
Note: Handling init family methods
We skipped the init family not just because it is highly unlikely but also because it behaves differently - init family methods consume the object reference they are called on, that is they expect to be passed an owned object which they take ownership of, and will release it if needed. Unsurprisingly consuming an argument is also indicated by an attribute, just as for returning a retained object. The curious reader might wish to determine the code required, even though needing it is highly unlikely.
[*] A "normal" selector is one for a method which follows the standard naming conventions of Objective-C and does not use attributes to alter the memory ownership behaviour in ways contrary to the standard conventions. Only supporting standard conventions is not a big restriction, the whole point of the conventions is that code relies on them!
[#] You are of course very unlikely to be passed a new family selector as well, callback
would usually have to be a reference to a class object, but handling it is the same as for the copy family so we've included it.