FDFullScreenPopGesture学习笔记

96
悲伤的盖茨比
2016.07.12 14:47* 字数 1094

这段时间,公司项目的app需要做全局手势返回,之前也有用过FDFullScreenPopGesture这个开源库,只不过原来要求比较低,就只是单纯的将源码放进去,没有过多研究。但是,目前手上的项目,由于全局使用同一个导航栏,而且,不同地方的导航栏底色不同,导致返回的时候吹出现很多问题。因此,花了一段时间来研究手势返回。

整个手势返回的实现,主要是通过runtime来做的。

Method Swizzling原理(http://blog.csdn.net/yiyaaixuexi/article/details/9374411

http://blog.sina.com.cn/s/blog_916e0cff0101ghxu.html)

每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的method实现。

+load vs. +initialize

Swizzling应该在+load方法中实现。

每个类的这两个方法会被Objective-C运行时系统自动调用,+load是在一个类最开始加载时调用,+initialize是在应用中第一次调用该类或它的实例的方式之前调用。这两个方法都是可选的,只有实现了才会被执行。

+ (void)load {

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

Class class = [self class];

SEL originalSelector = @selector(viewWillAppear:);

SEL swizzledSelector = @selector(fd_viewWillAppear:);

Method originalMethod = class_getInstanceMethod(class, originalSelector);

Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

//为该类添加一个方法

BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

if(success) {

//添加成功,直接替换

class_replaceMethod(class, originalSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));

} else {

//未添加成功,交换两个imp

method_exchangeImplementations(originalMethod, swizzledMethod);

}});}

选择器,方法及实现

1.选择器(typedef struct objc_selector *SEL):选择器用于表示一个方法在运行时的名字,一个方法的选择器是一个注册到(或映射到)Objective-C运行时中的C字符串,它是由编译器生成并在类加载的时候被运行时系统自动映射。

2.方法(typedef struct objc_method *Method):一个代表类定义中一个方法的不明类型。

3.实现(typedef id (*IMP)(id, SEL, ...)):这种数据类型是实现某个方法的函数开始位置的 指针,函数使用的是基于当前CPU架构的标准C调用规约。第一个参数是指向self的指针(也就是该类的某个实例的内存空间,或者对于类方法来说,是指向原类的指针)。第二个参数是方法的选择器,后面跟的都是参数。

理解的最好方式:一个类(Class)维护一张调度表(dispatch table)用于解析运行时发送的消息;调度表中的每个实体(entity)都是一个方法(Method),其中key值是一个唯一的名字-选择器(SEL),它对应到一个实现(IMP)--实际上就是指向标准C函数的指针。

在category中无法添加实例属性,因此添加属性的时候通过运行时添加

在@interface UIViewController (FDFullscreenPopGesturePrivate)中的 fd_willAppearInjectBlock属性

//get方法

- (_FDViewControllerWillAppearInjectBlock)fd_willAppearInjectBlock {

return objc_getAssociatedObject(self, _cmd);

}

//set方法

-(void)setFd_willAppearInjectBlock:(_FDViewControllerWillAppearInjectBlock)block {

objc_setAssociatedObject(self, @selector(fd_willAppearInjectBlock), block, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

UIViewController (FDFullScreenPopGesture)中只是简单地添加了几个属性,这几个属性的作用,都是在UINavigationController (FDFullScreenPopGesture)等相关文件中起作用。


UINavigationController (FDFullscreenPopGesture)

- (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {

//判断是否已经添加fd_xxxGesture,否的话,添加该手势 interactivePopGestureRecognizer是iOS7之后添加的左滑返回手势,此处,从该手势上的view的gestures上获得需要使用的属性

if(![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.fd_fullscreenPopGestureRecognizer]) {

[self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_fullscreenPopGestureRecognizer];

//获取左滑手势的所有targets

NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets'];

//获取相关target

id internalTarget = [internalTargets.firstObject valueForKey:@"target"];

//获取handleNavigationTransition:的sel

SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");

self.fd_fullscreenPopGestureRecognizer.delegate = self.fd_popGestureRecognizerDelegate;

//为该手势添加target和action

[self.fd_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];

self.interactivePopGestureRecognizer.enabled = NO;

}

[self fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];

if(![self.viewControllers containsObject:viewController]) {

[self fd_pushViewController:viewController animated:animated];

}

}

- (void)fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController {

if(!self.fd_viewControllerBasedNavigationBarAppearanceEnabled){

return;

}

__weak typeof(self) weakSelf = self;

_FDViewControllerWillAppearInjectBlock block = ^(UIViewController *viewController, BOOL animated) {

__strong typeof(weakSelf) strongSelf = weakSelf;

if(strongSelf) {

//此处的fd_prefersNavigationBarHidden属性就是另一个category中的

[strongSelf setNavigationBarHidden:viewController.fd_prefersNavigationBarHidden animated:animated];

}};

appearingViewController.fd_willAppearInjectBlock = block;

UIViewController *disappearingViewController = self.viewControllers.lastObject;

if(disappearingViewController && !disappearingViewController.fd_willAppearInjectBlock) {

disappearingViewController.fd_willAppearInjectBlock = block;

}}}

我的iOS学习之路
Gupao