Runtime 简称运行时,OC就是运行时机制
// OC:运行时机制,消息机制是运行时机制最重要的机制
//
消息机制:任何方法调用,本质都是发送消息
严格检查运行机制设置为no
调用类方法,本质也会将类转化为对象调用其方法
Person
*p = [[Person
alloc] init];
//
让p发送消息
objc_msgSend(p,
@selector(eat));
objc_msgSend(p,
@selector(run:),10);
//
获取类对象
Class personClass = [Person
class];
// [personClass performSelector:@selector(eat)];
//
运行时
objc_msgSend(personClass,
@selector(eat));
Runtime 交换方法(用系统的方法调用,不用每个文件引入分类头文件)
分类里面不能调用父类方法,只能用运行时
交换方法实现,方法都是定义在类里面
加载类方法中调用(load)
+ (void)load
{
//
交换方法实现,方法都是定义在类里面
// class_getMethodImplementation:获取类方法实现
// class_getInstanceMethod:获取对象方法
// class_getClassMethod:获取类方法
// IMP:方法实现
// imageNamed
// Class:获取哪个类方法
// SEL:获取方法编号,根据SEL就能去对应的类找方法
Method
imageNameMethod = class_getClassMethod([UIImage
class],
@selector(imageNamed:));
// xmg_imageNamed
Method
xmg_imageNamedMethod = class_getClassMethod([UIImage
class],
@selector(xmg_imageNamed:));
//
交换方法实现
method_exchangeImplementations(imageNameMethod, xmg_imageNamedMethod);
}
+ (UIImage
*)xmg_imageNamed:(NSString
*)imageName
{
// 1.加载图片
UIImage
*image = [UIImage
xmg_imageNamed:imageName];
// 2.判断功能
if (image ==
nil) {
NSLog(@"加载image为空");
}
return image;
}
Runtime 动态添加方法
有没有使用performSelector,有没有动态添加过方法
// performSelector:动态添加方法 (运行时才会报错)
//
动态添加方法,首先实现这个resolveInstanceMethod
// resolveInstanceMethod调用:当调用了没有实现的方法没有实现就会调用resolveInstanceMethod
// resolveInstanceMethod作用:就知道哪些方法没有实现,从而动态添加方法
// sel:没有实现方法
Person
*p = [[Person
alloc] init];
#import
"Person.h"
//
动态添加方法
// [p performSelector:@selector(eat)];
[p performSelector:@selector(eat:) withObject:@111];
//
定义函数
//
没有返回值,参数(id,SEL)
// void(id,SEL)
void
aaaa(id
self,
SEL
_cmd,
id param1)
{
NSLog(@"调用eat
%@ %@ %@",self,NSStringFromSelector(_cmd),param1);
}
//
默认一个方法都有两个参数,self,_cmd,隐式参数
// self:方法调用者
// _cmd:调用方法的编号
//
动态添加方法,首先实现这个resolveInstanceMethod
// resolveInstanceMethod调用:当调用了没有实现的方法没有实现就会调用resolveInstanceMethod
// resolveInstanceMethod作用:就知道哪些方法没有实现,从而动态添加方法
// sel:没有实现方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// NSLog(@"%@",NSStringFromSelector(sel));
//
动态添加eat方法
// if ([NSStringFromSelector(sel) isEqualToString:@"eat"]) {
//}
if (sel ==
@selector(eat:)) {
/*
cls:给哪个类添加方法
SEL:添加方法的方法编号是什么
IMP:方法实现,函数入口,函数名
types:方法类型
*/
// @:对象
:SEL
class_addMethod(self,
sel, (IMP)aaaa,
"v@:@");
//
处理完
return
YES;
}
return
[super
resolveInstanceMethod:sel];
}
Runtime 分类添加属性
例:给NSObject添加name属性
NSObject
*objc = [[NSObject
alloc] init];
objc.name
=
@"123";
NSLog(@"%@",objc.name);
@interface
NSObject (Objc)
@property
(nonatomic,
strong)
NSString
*name;
@end
#import
"NSObject+Objc.h"
#import
<objc/message.h>
@implementation
NSObject (Objc)
//static NSString *_name;
- (void)setName:(NSString
*)name
{
//
添加属性,跟对象
//
给某个对象产生关联,添加属性
// object:给哪个对象添加属性
// key:属性名,根据key去获取关联的对象
,void * == id
// value:关联的值
// policy:策越
objc_setAssociatedObject(self,
@"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// _name = name;
}
- (NSString
*)name
{
return
objc_getAssociatedObject(self,
@"name");
}
@end
Runtime 模型属性代码(字典转模型,解析字典自动生成属性代码)
NSObject+Property
#import
"NSObject+Property.h"
@implementation
NSObject (Property)
+ (void)createPropertyCodeWithDict:(NSDictionary
*)dict
{
NSMutableString
*strM = [NSMutableString
string];
//
遍历字典
[dict enumerateKeysAndObjectsUsingBlock:^(id
_Nonnull
propertyName,
id
_Nonnull
value,
BOOL *
_Nonnull
stop) {
// NSLog(@"%@ %@",propertyName,[value class]);
NSString
*code;
if ([value isKindOfClass:NSClassFromString(@"__NSCFString")])
{
code = [NSString
stringWithFormat:@"@property (nonatomic, strong) NSString *%@;",propertyName]
;
}else
if ([value isKindOfClass:NSClassFromString(@"__NSCFNumber")]){
code = [NSString
stringWithFormat:@"@property (nonatomic, assign) int %@;",propertyName]
;
}else
if ([value isKindOfClass:NSClassFromString(@"__NSCFArray")]){
code = [NSString
stringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",propertyName]
;
}else
if ([value isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){
code = [NSString
stringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",propertyName]
;
}else
if ([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){
code = [NSString
stringWithFormat:@"@property (nonatomic, assign) BOOL %@;",propertyName]
;
}
[strM appendFormat:@"\n%@\n",code];
}];
NSLog(@"%@",strM);
}
Runtime 字典转模型方式一 KVC
@interface
Status :
NSObject
@property
(nonatomic,
assign)
NSInteger ID;
//
模型的属性名跟字典一一对应
+ (__kindof
Status
*)statusWithDict:(NSDictionary
*)dict;
@implementation
Status
+ (Status
*)statusWithDict:(NSDictionary
*)dict
{
Status
*status = [[self
alloc] init];
// KVC
[status setValuesForKeysWithDictionary:dict];
return
status;
}
KVC字典转模型弊端:必须保证,模型中的属性和字典中的key一一对应。
- 如果不一致,就会调用[<Status 0x7fa74b545d60> setValue:forUndefinedKey:] 报key找不到的错。
- 分析:模型中的属性和字典的key不一一对应,系统就会调用setValue:forUndefinedKey:报错。
- 解决:重写对象的setValue:forUndefinedKey:,把系统的方法覆盖, 就能继续使用KVC,字典转模型了。
//
解决KVC报错
- (void)setValue:(id)value
forUndefinedKey:(NSString
*)key
{
if ([key isEqualToString:@"id"])
{
_ID = [value integerValue];
}
// key:没有找到key
// value:没有找到key对应的值
NSLog(@"%@ %@",key,value);
}
Runtime 字典转模型二 Runtime
KVC:遍历字典中所有key,去模型中查找有没有对应的属性名
runtime:遍历模型中所有属性名,去字典中查找
- 思路:利用运行时,遍历模型中所有属性,根据模型的属性名,去字典中查找key,取出对应的值,给模型的属性赋值。
- 步骤:提供一个NSObject分类,专门字典转模型,以后所有模型都可以通过这个分类转。
+ (instancetype)modelWithDict:(NSDictionary
*)dict{
//
创建对应类的对象
id objc = [[self
alloc] init];
// runtime:遍历模型中所有成员属性,去字典中查找
//
属性定义在哪,定义在类,类里面有个属性列表(数组)
//
遍历模型所有成员属性
// ivar:成员属性
// class_copyIvarList:把成员属性列表复制一份给你
// Ivar *:指向Ivar指针
// Ivar *:指向一个成员变量数组
// class:获取哪个类的成员属性列表
// count:成员属性总数
unsigned
int count = 0;
Ivar *ivarList = class_copyIvarList(self,
&count);
for (int
i = 0 ; i < count; i++) {
//
获取成员属性
Ivar ivar = ivarList[i];
//
获取成员名
NSString
*propertyName = [NSString
stringWithUTF8String:ivar_getName(ivar)];
;
//
成员属性类型
NSString
*propertyType = [NSString
stringWithUTF8String:ivar_getTypeEncoding(ivar)];
//
获取key
NSString
*key = [propertyName substringFromIndex:1];
//
获取字典的value
id value = dict[key];
//
给模型的属性赋值
// value:字典的值
// key:属性名
if (value) {
// KVC赋值:不能传空
[objc setValue:value forKey:key];
}
// NSLog(@"%@",key);
// NSLog(@"%@ %@",propertyType , propertyName);
}
return
objc;
}
//
二级转换
//
值是字典,成员属性的类型不是字典,才需要转换成模型
if ([value isKindOfClass:[NSDictionary
class]] && ![propertyType containsString:@"NS"])
{
//
需要字典转换成模型
//
转换成哪个类型
//
生成的是这种@"@\"User\""
类型
-》
@"User"
在OC字符串中
\" -> ",\是转义的意思,不占用字符
NSRange
range = [propertyType rangeOfString:@"\""];
propertyType = [propertyType substringFromIndex:range.location + range.length];
// User\"";
range = [propertyType rangeOfString:@"\""];
propertyType = [propertyType substringToIndex:range.location];
//
字符串截取
//
获取需要转换类的类对象
Class modelClass = NSClassFromString(propertyType);
if (modelClass) {
value = [modelClass
modelWithDict:value];
}
}