Runtime - 运行时 理解和应用 字典转模型框架 AFN中的交换方法
2016-03-23 20:24
459 查看
运行时是一种面向对象的编程语言的运行环境,类似于java的虚拟机;
OC的最主要特点,就在于其程序运行时,以发送消息的方式调用方法;
当我们调用方法时,实际上是通过发送消息的方式在列表中查找方法,
每一个类对象(类本质上也是对象)中都有一个对象方法列表,即对象方法缓存,每一个元类对象中都有一个类方法列表,即类方法缓存;方法列表中,每个方法结构体都记录着方法的名称、方法实现、参数类型;通过selector能找到对应的IMP地址;
运行时在开发中的主要应用场景有:
字典转模型;
给分类增加关联对象,从而在开发框架时解耦;
交换方法,当我们无法修改系统方法或第三方框架时,可利用交换方法先执行自己的方法,在执行系统或第三方框架的方法;
字典转模型:
#import "NSObject+Runtime.h"
#import <objc/runtime.h>
@implementation NSObject(Runtime)
// 所有字典转模型框架,核心算法!
+ (instancetype)z_objWithDict:(NSDictionary*)dict {
// 实例化对象
idobject = [[self
alloc] init];
// 使用字典,设置对象信息
// 1> 获得self
的属性列表
NSArray *proList = [self
z_objProperties];
// 2> 遍历字典
[dict enumerateKeysAndObjectsUsingBlock:^(id
_Nonnull key, id
_Nonnull obj, BOOL *
_Nonnull stop) {
NSLog(@"key%@ --- value %@", key,obj);
// 3> 判断 key
是否在 proList
中
if ([proList
containsObject:key]) {
// 说明属性存在,可以使用 `KVC`
设置数值
[object setValue:obj
forKey:key];
}
}];
return object;
}
const char *kPropertiesListKey =
"ZPropertiesListKey";
+ (NSArray *)z_objProperties {
// --- 1. 从`关联对象`中获取对象属性,如果有,直接返回!
/**
获取关联对象 -
动态添加的属性
参数:
1.对象 self
2.动态属性的 key
返回值
动态添加的`属性值`
*/
NSArray *ptyList =
objc_getAssociatedObject(self,
kPropertiesListKey);
if(ptyList !=
nil) {
return ptyList;
}
// 调用运行时方法,取得类的属性列表
// Ivar 成员变量
// Method 方法
// Property 属性
// Protocol 协议
/**
参数
1.要获取的类
2.类属性的个数指针
返回值
所有属性的`数组`,C
语言中,数组的名字,就是指向第一个元素的地址
retain/create/copy 需要 release,最好 option + click
*/
unsigned
int count = 0;
objc_property_t *proList =
class_copyPropertyList([self
class], &count);
NSLog(@"属性的数量 %d", count);
// 创建数组
NSMutableArray *arrayM = [NSMutableArray
array];
// 遍历所有的属性
for (unsigned
int i = 0; i < count; i++) {
// 1. 从数组中取得属性
/**
C 语言的结构体指针,通常不需要 `*`
*/
objc_property_t pty = proList[i];
// 2. 从 pty
中获得属性的名称
const
char *cName = property_getName(pty);
NSString *name = [NSString
stringWithCString:cName
encoding:NSUTF8StringEncoding];
// NSLog(@"%@", name);
// 3. 属性名称添加到数组
[arrayM addObject:name];
}
// 释放数组
free(proList);
// --- 2. 到此为止,对象的属性数组已经获取完毕,利用关联对象,动态添加属性
/**
参数
1.对象 self [OC
中class 也是一个特殊的对象]
2.动态添加属性的 key,获取值的时候使用
3.动态添加的属性值
4.对象的引用关系
*/
objc_setAssociatedObject(self,
kPropertiesListKey, arrayM.copy,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return arrayM.copy;
}
@end
基本思路:通过运行时方法获取类的属性列表,遍历列表获取属性,遍历字典对属性进行复制,这是第三方字典转模型框架的核型思路;
为了避免每次字典转模型都获取类的属性,运用关联对象,动态添加属性,下次判断关联对象动态添加的属性部位空时,直接return;
AFN中就用到了交换方法:
在AFURLSessionManager.m中
static inline
voidaf_swizzleSelector(Class theClass,
SEL originalSelector, SELswizzledSelector) {
Method originalMethod =class_getInstanceMethod(theClass, originalSelector);
Method swizzledMethod =class_getInstanceMethod(theClass, swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
}
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass{
Method afResumeMethod =class_getInstanceMethod(self,
@selector(af_resume));
Method afSuspendMethod =class_getInstanceMethod(self,
@selector(af_suspend));
if(af_addMethod(theClass,
@selector(af_resume),afResumeMethod)) {
af_swizzleSelector(theClass, @selector(resume),@selector(af_resume));
}
if(af_addMethod(theClass,
@selector(af_suspend),afSuspendMethod)) {
af_swizzleSelector(theClass, @selector(suspend),@selector(af_suspend));
}
}
- (void)af_resume{
NSAssert([selfrespondsToSelector:@selector(state)],
@"Does notrespond to state");
NSURLSessionTaskState state = [self state];
[self af_resume];
if (state !=NSURLSessionTaskStateRunning) {
[[NSNotificationCenter defaultCenter]postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
}
}
- (void)af_suspend{
NSAssert([selfrespondsToSelector:@selector(state)],
@"Does notrespond to state");
NSURLSessionTaskState state = [self state];
[self af_suspend];
if (state !=NSURLSessionTaskStateSuspended) {
[[NSNotificationCenter defaultCenter]postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
}
}
通过交换方法resume为自定义的af_resume,在af_resume中再调用resume,同时发出通知,实现了对resume的监听;
OC的最主要特点,就在于其程序运行时,以发送消息的方式调用方法;
当我们调用方法时,实际上是通过发送消息的方式在列表中查找方法,
每一个类对象(类本质上也是对象)中都有一个对象方法列表,即对象方法缓存,每一个元类对象中都有一个类方法列表,即类方法缓存;方法列表中,每个方法结构体都记录着方法的名称、方法实现、参数类型;通过selector能找到对应的IMP地址;
运行时在开发中的主要应用场景有:
字典转模型;
给分类增加关联对象,从而在开发框架时解耦;
交换方法,当我们无法修改系统方法或第三方框架时,可利用交换方法先执行自己的方法,在执行系统或第三方框架的方法;
字典转模型:
#import "NSObject+Runtime.h"
#import <objc/runtime.h>
@implementation NSObject(Runtime)
// 所有字典转模型框架,核心算法!
+ (instancetype)z_objWithDict:(NSDictionary*)dict {
// 实例化对象
idobject = [[self
alloc] init];
// 使用字典,设置对象信息
// 1> 获得self
的属性列表
NSArray *proList = [self
z_objProperties];
// 2> 遍历字典
[dict enumerateKeysAndObjectsUsingBlock:^(id
_Nonnull key, id
_Nonnull obj, BOOL *
_Nonnull stop) {
NSLog(@"key%@ --- value %@", key,obj);
// 3> 判断 key
是否在 proList
中
if ([proList
containsObject:key]) {
// 说明属性存在,可以使用 `KVC`
设置数值
[object setValue:obj
forKey:key];
}
}];
return object;
}
const char *kPropertiesListKey =
"ZPropertiesListKey";
+ (NSArray *)z_objProperties {
// --- 1. 从`关联对象`中获取对象属性,如果有,直接返回!
/**
获取关联对象 -
动态添加的属性
参数:
1.对象 self
2.动态属性的 key
返回值
动态添加的`属性值`
*/
NSArray *ptyList =
objc_getAssociatedObject(self,
kPropertiesListKey);
if(ptyList !=
nil) {
return ptyList;
}
// 调用运行时方法,取得类的属性列表
// Ivar 成员变量
// Method 方法
// Property 属性
// Protocol 协议
/**
参数
1.要获取的类
2.类属性的个数指针
返回值
所有属性的`数组`,C
语言中,数组的名字,就是指向第一个元素的地址
retain/create/copy 需要 release,最好 option + click
*/
unsigned
int count = 0;
objc_property_t *proList =
class_copyPropertyList([self
class], &count);
NSLog(@"属性的数量 %d", count);
// 创建数组
NSMutableArray *arrayM = [NSMutableArray
array];
// 遍历所有的属性
for (unsigned
int i = 0; i < count; i++) {
// 1. 从数组中取得属性
/**
C 语言的结构体指针,通常不需要 `*`
*/
objc_property_t pty = proList[i];
// 2. 从 pty
中获得属性的名称
const
char *cName = property_getName(pty);
NSString *name = [NSString
stringWithCString:cName
encoding:NSUTF8StringEncoding];
// NSLog(@"%@", name);
// 3. 属性名称添加到数组
[arrayM addObject:name];
}
// 释放数组
free(proList);
// --- 2. 到此为止,对象的属性数组已经获取完毕,利用关联对象,动态添加属性
/**
参数
1.对象 self [OC
中class 也是一个特殊的对象]
2.动态添加属性的 key,获取值的时候使用
3.动态添加的属性值
4.对象的引用关系
*/
objc_setAssociatedObject(self,
kPropertiesListKey, arrayM.copy,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return arrayM.copy;
}
@end
基本思路:通过运行时方法获取类的属性列表,遍历列表获取属性,遍历字典对属性进行复制,这是第三方字典转模型框架的核型思路;
为了避免每次字典转模型都获取类的属性,运用关联对象,动态添加属性,下次判断关联对象动态添加的属性部位空时,直接return;
AFN中就用到了交换方法:
在AFURLSessionManager.m中
static inline
voidaf_swizzleSelector(Class theClass,
SEL originalSelector, SELswizzledSelector) {
Method originalMethod =class_getInstanceMethod(theClass, originalSelector);
Method swizzledMethod =class_getInstanceMethod(theClass, swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
}
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass{
Method afResumeMethod =class_getInstanceMethod(self,
@selector(af_resume));
Method afSuspendMethod =class_getInstanceMethod(self,
@selector(af_suspend));
if(af_addMethod(theClass,
@selector(af_resume),afResumeMethod)) {
af_swizzleSelector(theClass, @selector(resume),@selector(af_resume));
}
if(af_addMethod(theClass,
@selector(af_suspend),afSuspendMethod)) {
af_swizzleSelector(theClass, @selector(suspend),@selector(af_suspend));
}
}
- (void)af_resume{
NSAssert([selfrespondsToSelector:@selector(state)],
@"Does notrespond to state");
NSURLSessionTaskState state = [self state];
[self af_resume];
if (state !=NSURLSessionTaskStateRunning) {
[[NSNotificationCenter defaultCenter]postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
}
}
- (void)af_suspend{
NSAssert([selfrespondsToSelector:@selector(state)],
@"Does notrespond to state");
NSURLSessionTaskState state = [self state];
[self af_suspend];
if (state !=NSURLSessionTaskStateSuspended) {
[[NSNotificationCenter defaultCenter]postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
}
}
通过交换方法resume为自定义的af_resume,在af_resume中再调用resume,同时发出通知,实现了对resume的监听;
相关文章推荐
- android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
- java显示当前运行时的参数(java运行参数)
- OC - 9.基于Quartz2D绘制下载进度条(demo)
- iOS学习之Objective-C 2.0 运行时系统编程
- oc 的一些概念
- [代码例程] iPhone开发入门(7)--- 从C/C++语言到Objective-C语
- IOS 面试习题 Object-C
- objective-c block 讲解
- IOS求职之OC面试题
- iOS OC和Swift混编
- OC-RunTime-Method Swizzling
- OC_继承,初始化
- OC 省市区划分
- iOS开发 — Quartz 2D知识点应用 (制作了一个Demo,源代码)
- OC 自定义 get/set 方法注意点
- OC 书签管理系统
- 编写 Objective-C 代码/掌握基本的编程技能 之 读后笔记
- Swift 和 OC 混编
- 利用UIScrollView实现展示图片的无限滚动及自动滚动
- Objective-C 类,对象,属性,方法