前言:這是我偶然間看見的一種利用runtime原理寫向右側滑返回上一頁的類擴展,
用起來很方便,直接將擴展拉進項目里面即可,然后所有的push的控制器都可以右滑返回上一頁了
首先需要了解一下 runtme的關聯(lián)方法objc_setAssociatedObject
關聯(lián)對象不是為類\對象添加屬性或者成員變量(因為在設置關聯(lián)后也無法通過ivarList或者propertyList取得) ,而是為類添加一個相關的對象,通常用于存儲類信息,例如存儲類的屬性列表數(shù)組,為將來字典轉模型的方便。
objc_setAssociatedObject方法的參數(shù)解釋:
第一個參數(shù)id object, 當前對象
第二個參數(shù)const void *key, 關聯(lián)的key,是c字符串
第三個參數(shù)id value, 被關聯(lián)的對象的值
第四個參數(shù)objc_AssociationPolicy policy關聯(lián)引用的規(guī)則
使用方式一:給分類添加屬性
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 給系統(tǒng)NSObject類動態(tài)添加屬性name
NSObject *objc = [[NSObject alloc] init];
objc.name = @"哈哈";
NSLog(@"%@",objc.name);
}
@end
// 定義關聯(lián)的key
static const char *key = "name";
@implementation NSObject (Property)
- (NSString *)name
{
// 根據(jù)關聯(lián)的key,獲取關聯(lián)的值。
return objc_getAssociatedObject(self, key);
}
- (void)setName:(NSString *)name
{
// 第一個參數(shù):給哪個對象添加關聯(lián)
// 第二個參數(shù):關聯(lián)的key,通過這個key獲取
// 第三個參數(shù):關聯(lián)的value
// 第四個參數(shù):關聯(lián)的策略
objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end```
使用方式二:給對象添加關聯(lián)對象。
/**
刪除點擊
@param recId 購物車ID
*/
- (void)shopCartCell:(BSShopCartCell *)shopCartCell didDeleteClickedAtRecId:(NSString *)recId
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"確認要刪除這個寶貝" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
// 傳遞多參數(shù)
objc_setAssociatedObject(alert, "suppliers_id", @"1", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(alert, "warehouse_id", @"2", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
alert.tag = [recId intValue];
[alert show];
}
/**
- 確定刪除操作
*/
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
NSString *warehouse_id = objc_getAssociatedObject(alertView, "warehouse_id");
NSString *suppliers_id = objc_getAssociatedObject(alertView, "suppliers_id");
NSString *recId = [NSString stringWithFormat:@"%ld",(long)alertView.tag];
}
}
下面是右滑返回 ,我做了詳細注釋,
import@interface UINavigationController (XWFullScreenLeftSlidPop)
@property(strong, nonatomic) UIPanGestureRecognizer * xw_popgestureRecoginizer;
@end```
//// UINavigationController+XWFullScreenLeftSlidPop.m// KouDaiGuangBo//// Created by 文 on 2016/12/26.// Copyright ? 2016年 CSC. All rights reserved.//#import "UINavigationController+XWFullScreenLeftSlidPop.h"#import@interface XWFullScreenPopGestureRecognizerDelegate :NSObject@property(weak, nonatomic) UINavigationController * navigationController;
@end
@implementation XWFullScreenPopGestureRecognizerDelegate
-(BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
NSLog(@"----%ld",self.navigationController.viewControllers.count);
// 判斷是否是更新
// if (self.navigationController.viewControllers.count<=1) {
//
// return NO;
// }
// 如果正在轉場動畫
if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {
return NO;
}
//判斷手指移動方向
CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
if (translation.x<=0) {
// 左滑
return NO;
}
return YES;
}
@end
@implementation UINavigationController (XWFullScreenLeftSlidPop)
+(void)load
{
// 交叉方法替換系統(tǒng)的 pushViewController
Method methodNomer = class_getInstanceMethod([self class], @selector(pushViewController:animated:));
Method othermethod = class_getInstanceMethod([self class],@selector(XW_pushViewController:animated:));
method_exchangeImplementations(methodNomer, othermethod);
}
-(void)XW_pushViewController:(UIViewController *)ViewController animated:(BOOL)animated
{
// 替換的目的是為了 添加一個自己的手勢
//拿到navigationController原有的pop手勢:self.interactivePopGestureRecognizer
// self.interactivePopGestureRecognizer是navigationController自帶的pop手勢
if(![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.xw_popgestureRecoginizer])// 判斷是否是自己的手勢
{
// 添加自己的手勢
[self.interactivePopGestureRecognizer.view addGestureRecognizer:self.xw_popgestureRecoginizer];
NSArray * tagets =[self.interactivePopGestureRecognizer valueForKey:@"targets"];
id internalTarget = [tagets.firstObject valueForKey:@"target"];
SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
// 攔截系統(tǒng)的所有的handleNavigationTransition:換成自己自己添加的手勢來識別
self.xw_popgestureRecoginizer.delegate = [self xw_fullscreenPopGestuieRecoginzerDelegate];
// 自己的手勢調用系統(tǒng)的手勢方法 handleNavigationTransition
[self.xw_popgestureRecoginizer addTarget:internalTarget action:internalAction];
// 禁止系統(tǒng)的手勢交互
self.interactivePopGestureRecognizer.enabled = NO;
}
if (![self.viewControllers containsObject:ViewController]) {
// 交叉方法調用系統(tǒng)的pushViewController:方法
// 調用XW_pushViewController = 調用pushViewController 因為這兩個方法互換了
[self XW_pushViewController:ViewController animated:animated];
}
}
-(XWFullScreenPopGestureRecognizerDelegate*)xw_fullscreenPopGestuieRecoginzerDelegate
{
// 給navigationController 添加一個xw_fullscreenPopGestuieRecoginzerDelegate 屬性
// 獲取關聯(lián)對象
XWFullScreenPopGestureRecognizerDelegate *delegate = objc_getAssociatedObject(self, _cmd);
//如果未關聯(lián)重新關聯(lián)
if (!delegate) {
delegate = [[XWFullScreenPopGestureRecognizerDelegate alloc] init];
objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//返回關聯(lián)對象
return delegate;
}
-(UIPanGestureRecognizer *)xw_popgestureRecoginizer
{
// 給navigationController 添加一個xw_popgestureRecoginizer屬性
// 獲取關聯(lián)對象
UIPanGestureRecognizer *panGestureRecoginizer =objc_getAssociatedObject(self, _cmd);
//如果未關聯(lián)重新關聯(lián)
if (!panGestureRecoginizer) {
panGestureRecoginizer =[[UIPanGestureRecognizer alloc] init];
panGestureRecoginizer.maximumNumberOfTouches = 1;
//將self與panGestureRecoginizer關聯(lián)起來
objc_setAssociatedObject(self, _cmd, panGestureRecoginizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//返回關聯(lián)對象
return panGestureRecoginizer;
}
@end```