至少有两种方法可以做到这一点。
下标
使用objectForKeyedSubscript:
和setObject:forKeyedSubscript:
@property (nonatomic,strong) NSMutableDictionary *properties;
- (id)objectForKeyedSubscript:(id)key {
return [[self properties] valueForKey:[NSString stringWithFormat:@"%@",key]];
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
[[self properties] setValue:object forKey:[NSString stringWithFormat:@"%@",key]];
}
Person *p = [Person new];
p[@"name"] = @"Jon";
NSLog(@"%@",p[@"name"]);
解决实例方法:
这是运行时为所有方法执行的 objc_sendMsg:
如果您查看底部,您有机会看到resolveInstanceMethod:
,这使您可以将方法调用重定向到您选择的一个。要回答您的问题,您需要编写一个通用的 getter 和 setter 来查找字典 ivar 上的值:
// generic getter
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}
// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
// delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
然后实现resolveInstanceMethod:
将请求的方法添加到类中。
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:@"set"]) {
class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v@:@");
} else {
class_addMethod([self class], aSEL,(IMP)propertyIMP, "@@:");
}
return YES;
}
您也可以为该方法返回一个 NSMethodSignature ,然后将其包装在 NSInvocation 中并传递给forwardInvocation:
,但添加该方法更快。
这是在 CodeRunner 中运行的要点。它不处理myClass["anyProperty"]
呼叫。