runtime精选和blockiOS开发iOS 开发

runtime之全屏滑动移除控制器

2016-12-18  本文已影响310人  coderYJ

最近有朋友想了解runtime在这里军哥就浅析一下runtime

UIGestureRecognizer *ges = self.interactivePopGestureRecognizer;
<UIScreenEdgePanGestureRecognizer: 0x7f860f70d460; state = Possible; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x7f860f401fa0>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f860f70cfe0>)>>

其实细心的朋友就发现了,并没有我们要的值,我们要的是全屏,什么叫全屏,有的朋友说上下左右不是全屏吗? 其实不是,因为还有中间呢?
这个值默认是左侧,也就是我们经常用的从左侧边缘滑动移除控制器,如果不信,你可以打开你的iPhone的设置界面,随便push一个控制器,然后从左侧边缘按住屏幕往右滑,这个就是左侧滑动移除控制器,有的朋友说你为什么不让打开应用呢,因为现在有的应用把这个功能取消了,这个功能是在iOS7之后才有的
第一种方案pass掉了

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGes:)];
    [self.view addGestureRecognizer:pan];
<UIScreenEdgePanGestureRecognizer: 0x7f860f70d460; state = Possible; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x7f860f401fa0>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f860f70cfe0>)>>

你有没有发现action=handleNavigationTransition:到此我们的action是有了,那现在唯一缺的就是Target

id target = [ges valueForKeyPath:@""];

但是用KVC的前提条件是必须知道这个属性的真实类型,才能取出,很显然现在我们是不知道的,所以接下来我们的终极目的就是得到target的真实属性,那么怎么才能得到呢,接下来军哥就要放大招了,那就是runtime

有的朋友不知道什么是函数库,其实你稍微有一点点OC编程经验的就知道,函数库其实就是封装了好多方法供你调用,其实他也没有什么牛xx之处

initWithTarget:action这个方法在UIPanGestureRecognizer这个类下面
/**
     获取某一个类下面的所有成员属性
     @param cls#> 获取的那个类
     @param outCount#> 这个类下面的成员属性的个数
     @return 返回这个类下面的成员属性数组
     */
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([UIPanGestureRecognizer class], &outCount);
/**
     获取某一个类下面的所有成员属性
     cls 获取的那个类
     outCount这个类下面的成员属性的个数
     返回这个类下面的成员属性数组
     */
    unsigned int outCount = 0;
    // 说明 Ivar是C语言的成员变量,这个方法是拷贝一份这个类下面的成员变量
    Ivar *ivars = class_copyIvarList([UIGestureRecognizer class], &outCount);
    for (int i = 0; i< outCount; i++) {
        //ivar_getName 获取某一个成员变量下面的名称,因为这个方法返回的类型是const char *所以需要把char转换为NSString,直接包装成对象就可以了
       NSString *name = @(ivar_getName(ivars[i]));
        NSLog(@"%@",name);
    }
// 打印,输出了很多成员属性,其中最重要的成员属性是_targets,据此我们猜测,target可能存在于_targets里面,然后我们尝试一下
    id target = [ges valueForKeyPath:@"_targets"];
    NSLog(@"-- %@",target);

打印输出

2016-12-18 22:30:00.698 runtime之全屏滑动移除控制器[12311:313247] -- (
    "(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fd16dc01bf0>)"
)

如果做过后台的朋友就知道,看到()代表是数组,所以他返回的仍然是数组,其实也很好理解,为什么呢,因为假如你添加了很多手势,所有的target都在这个下面

NSArray *targetArray = [ges valueForKeyPath:@"_targets"];
    // 去掉数组
    id target = targetArray[0];
    NSLog(@"-- %@",target);

去掉数组打印如下

2016-12-18 22:33:13.766 runtime之全屏滑动移除控制器[12362:315288] -- (action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7ff7c9d073e0>)
UIGestureRecognizer *ges = self.interactivePopGestureRecognizer;
    // 打印,输出了很多成员属性,其中最重要的成员属性是_targets,据此我们猜测,target可能存在于_targets里面,然后我们尝试一下
    NSArray *targetArray = [ges valueForKeyPath:@"_targets"];
    // 去掉数组
    id tempTarget = targetArray[0];
    // 获取target
    id target = [tempTarget valueForKeyPath:@"_target"];
    
    // 消除方法弃用(过时)的警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    // 添加全屏滑动手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
#pragma clang diagnostic pop
    [self.view addGestureRecognizer:pan];

ps: #pragma clang diagnostic push是为了消除警告
具体可以参照我的另一篇文章iOS消除警告

    UIGestureRecognizer *ges = self.interactivePopGestureRecognizer;
    // 打印,输出了很多成员属性,其中最重要的成员属性是_targets,据此我们猜测,target可能存在于_targets里面,然后我们尝试一下
    NSArray *targetArray = [ges valueForKeyPath:@"_targets"];
    // 去掉数组
    id tempTarget = targetArray[0];
    // 获取target
    id target = [tempTarget valueForKeyPath:@"_target"];
    // 消除方法弃用(过时)的警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    // 添加全屏滑动手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
#pragma clang diagnostic pop
    [self.view addGestureRecognizer:pan];
    
    pan.delegate = self;
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if (self.viewControllers.count > 1) {
        // 非根控制器
        return YES;
    }else{
        // 跟控制器
        return NO;
    }
}

到此大功告成,小伙伴们,可以去试一下
如果你对runtime还有点晕的话,我自己录制的视频可以参考一下
链接: https://pan.baidu.com/s/1miJgfBM 密码: ah5u
示例代码

持续更新实用的干货
微信公众号iOS精汇
简书coderYJ,微博coderYJ

上一篇 下一篇

猜你喜欢

热点阅读