FDFullScreenPopGesture學習筆記

這段時間,公司項目的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;

}}}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,768評論 0 9
  • 我們常常會聽說 Objective-C 是一門動態語言,那么這個「動態」表現在哪呢?我想最主要的表現就是 Obje...
    Ethan_Struggle閱讀 2,231評論 0 7
  • 前言 runtime其實在我們日常開發過程中很少使用到,尤其是像我現在比較初級的程序猿就更用不到了。但是去面試很多...
    WolfTin閱讀 658評論 0 2
  • 繼上Runtime梳理(四) 通過前面的學習,我們了解到Objective-C的動態特性:Objective-C不...
    小名一峰閱讀 770評論 0 3
  • Expressions Nath, watching his sister's eyes blink and re...
    棕二閱讀 395評論 1 0