@dynamic属性用于通知编辑器不要生成属性对应的实例变量和setter getter 方法,但是在编译时期调用对应的存取方法不会报错,再次验证了OC是一门动态语言
#import <Foundation/Foundation.h>
@interface AutoDictionary : NSObject
@property (nonatomic, copy) NSString *string;
@property (nonatomic, strong) NSNumber *number;
@property (nonatomic, strong) NSDate *date;
@end
#import "AutoDictionary.h"
@interface AutoDictionary ()
@property (nonatomic, strong) NSMutableDictionary *dic;
@end
@implementation AutoDictionary
@dynamic string,date,number;
@end
VC里面调用如下:
#import "AutoDictionary.h"
@interface ViewController ()
@property (nonatomic, strong) AutoDictionary *autoDict;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.autoDict = [[AutoDictionary alloc] init];
[self.autoDict setNumber:[NSNumber numberWithInt:30]];
self.autoDict.string = [NSString stringWithFormat:@"i an"];
NSLog(@"number %@,string %@",self.autoDict.number,self.autoDict.string);
}
崩溃信息如下:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AutoDictionary setNumber:]: unrecognized selector sent to instance 0x60800001c200
利用运行时动态添加存取方法
#import "AutoDictionary.h"
#import <objc/runtime.h>
@interface AutoDictionary ()
@property (nonatomic, strong) NSMutableDictionary *backStore;
@end
@implementation AutoDictionary
@dynamic string,date,number;
-(instancetype)init{
self = [super init];
if (self) {
_backStore = [NSMutableDictionary new];
}
return self;
}
+(BOOL)resolveInstanceMethod:(SEL)sel{
NSString *selName = NSStringFromSelector(sel);
if ([selName hasPrefix:@"set"]) {
class_addMethod(self, sel, (IMP)autoDictSetter, "V@:@");
return YES;
}else{
class_addMethod(self, sel, (IMP)autoDictGetter, "@@:");
return YES;
}
}
void autoDictSetter(id self,SEL _cmd,id value){
AutoDictionary *typeSelf = (AutoDictionary *)self;
NSMutableDictionary *backStore = typeSelf.backStore;
// the selector will be for example ,'setNumber:'
// we need to remove ':' & 'set'
// SEL类型转为字符串类型
NSString *selectorString = NSStringFromSelector(_cmd);
// 可变字符串才可以进行一系列的替换 删除 操作
NSMutableString *key = [selectorString mutableCopy];
// remove the ':' at the end
[key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];
// remove the 'set' prefix
[key deleteCharactersInRange:NSMakeRange(0, 3)];
//lower first character
NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar];
if (value) {
[backStore setObject:value forKey:key];
}else{
[backStore removeObjectForKey:key];
}
}
id autoDictGetter(id self,SEL _cmd){
AutoDictionary *typedSelf = (AutoDictionary *)self;
NSMutableDictionary *backStore = typedSelf.backStore;
NSString *key = NSStringFromSelector(_cmd);
return [backStore objectForKey:key];
}
@end