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.