通过运行时机制可以获取到苹果一些私有(没有暴露在外的属性),通过kvc后可以取出来进行修改
使用运行时机制需要先导入头文件#import <objc/runtime.h>
例子:
- 正常情况下,导航栏是有个左侧滑动返回到上一个界面的功能的,但是,如何将它变成全屏滑动返回呢?
- 已知系统是通过导航控制器的interactivePopGestureRecognizer来返回的,这是一个手势,打印出来后发现是UIScreenEdgePanGestureRecognizer,创建这样一个对象
- 既然这是一个手势,那在屏幕左侧边缘滑动的时候必然会调用某个对象的某个方法,来返回到上一个界面的, 那么我们是否可以创建一个pan手势,调用这个对象的这个方法?
- 先用运行时打印这个手势,获得成员属性数组
unsigned int count = 0;
// 获取UIGestureRecognizer里所有的成员属性数组
Ivar *ivars = class_copyIvarList([UIGestureRecognizer class], &count);
- 再用for循环打印成员属性列数组,发现里面有一个_targets属性
for (int i = 0; i < count; i++) {
// 获取成员属性
Ivar ivar = ivars[i];
// 获取成员属性的属性名
NSString *name = @(ivar_getName(ivar));
// NSLog(@"%@",name);
}
- 通过打印发现_targets是一个数组,取出其中一个,继续打印,发现是个UIGestureRecognizerTarget对象,再打印,发现里面就是调用的对象与方法
//发现里面的targets是一个数组,继续向下
NSArray *targets = [gesture valueForKeyPath:@"_targets"];
//发现是个UIGestureRecognizerTarget对象,继续向下,发现里面就是调用对象及方法
id targetGesture = targets[0];
//(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition>)
//通过kvc取出对象
id target = [targetGesture valueForKeyPath:@"target"];
- 就可以根据这个对象target与action方法,来创建pan手势了
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:target action:@selector(handleNavigationTransition:)];
- 运行后发现的确可以全屏滑动返回了,但是仍然有bug。就是导航控制器的根控制器页面也可以滑动,而且一旦滑动,这个页面就挂了
- 这个时候需要先设置pan的代理,再在手势是否该执行的这个方法中添加判断条件return self.childViewControllers.count > 1;
只有当当前页面不是根控制器才激活手势