Apple docs on Dynamic Method Resolution
UPDATED FOR ARC BELOW.
If you want a class to respond to a given method w/o knowing what that method is when coding, you can use Dynamic Method Resolution.
In my case, I wanted to store some values in a dictionary not knowing what would be stored there (JSON parsed into a dictionary). Then have my class respond to getters/setters by looking for the given item as a key in the dictionary.
The answer here by Amy Worrall provides the bulk of the solution.
Basically you override resolveInstanceMethod: to call class_addMethod which adds accessorSetter or accessorGetter depending on the method being attempted.
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
NSString *method = NSStringFromSelector(aSEL);
if ([method hasPrefix:@"set"])
{
class_addMethod([self class], aSEL, (IMP) accessorSetter, "v@:@");
return YES;
}
else
{
class_addMethod([self class], aSEL, (IMP) accessorGetter, "@@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
Then implement those added methods, accessorSetter or accessorGetter, (I changed NSString to NSObject to allow for various class types to be stored in my dictionary. Also, for the setter, I remove ‘set’ and lowercase the next letter to turn something like setYikityBlar to yikityBlar)…
NSObject* accessorGetter(id self, SEL _cmd)
{
NSString *method = NSStringFromSelector(_cmd);
// Return the value of whatever key based on the method name
return [((EventItem *)self)->valDict objectForKey:method];
}
void accessorSetter(id self, SEL _cmd, NSObject* newValue)
{
NSString *method = NSStringFromSelector(_cmd);
// remove set
NSString *anID = [[method stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""]
stringByReplacingOccurrencesOfString:@":" withString:@""];
NSString *firstLowerChar = [[anID substringToIndex:1] lowercaseString];
anID = [anID stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:firstLowerChar];
// Set value of the key anID to newValue
[((EventItem *)self)->valDict setValue:newValue forKey:anID];
}
UPDATE FOR ARC:
ARC requires a bit more precision in the interface declaration – otherwise you get compile errors. There’s a couple things you should be able to do. If you actually have the item you want to dynamically create the getter/setters for, you can declare the methods to be dynamic (see link at the top of this post).
However, in my case, I don’t have them as properties (I set them in another class like a dictionary). So I declared the getters/setters in the header, but don’t implement them. I do get a compiler warning that my class’ implementation is incomplete. If anyone has a better solution, let me know.