為了不再重新寫個(gè)方法來破壞代碼可讀性胸嘴,那就調(diào)用一個(gè)帶有block的方法來完成對(duì)事件處理方法的回調(diào)雏掠。那怎么才能調(diào)用這個(gè)方法呢?Category劣像。做iOS開發(fā)的都知道UIButton的繼承關(guān)系,如下
UIButton-->UIControl-->UIView-->UIResponder-->NSObject
這個(gè)控件的創(chuàng)建設(shè)置以及用法就不多說了憨琳,下面說說今天的重點(diǎn)椎侠。以UIButton為例姿染,平時(shí)在用UIButton的時(shí)候伐憾,給當(dāng)前button添加事件處理方法就是調(diào)用它的addTarget:<#(nonnull id)#> action:<#(nonnull SEL)#> events:<#(customButtonType)#>
勉痴,然后再在方法里完成對(duì)事件的處理。但是這樣寫的話树肃,代碼的閱讀性就降低了很多蒸矛,那怎么寫才能在創(chuàng)建這個(gè)button地方順帶將它的事件處理方法就敲了呢?
但是給UIButton添加之后Category之后不可能就只寫我們這一次要做的事件處理啊乡话,怎么辦?畢竟是給button添加方法耳奕,每個(gè)button都有不同的事件處理绑青,這個(gè)時(shí)候Runtime就能幫我們一個(gè)大忙-動(dòng)態(tài)綁定。具體實(shí)現(xiàn):
.h
//
// UIButton+block.h
// RuntimeTest
//
// Created by Hongfei Zhai on 2017/11/22.
// Copyright ? 2017年 Hongfei Zhai. All rights reserved.
//
#import <UIKit/UIKit.h>
//使用runtime調(diào)用的庫(kù)
#import <objc/runtime.h>
typedef void(^TouchBlock)(UIButton *sender);
@interface UIButton (block)
- (void)touchWithEvents:(UIControlEvents )controlEvents withBlock:(TouchBlock)touchBlock;
@end
.m
//
// UIButton+block.m
// RuntimeTest
//
// Created by Hongfei Zhai on 2017/11/22.
// Copyright ? 2017年 Hongfei Zhai. All rights reserved.
//
#import "UIButton+block.h"
static const void *TouchKey = &TouchKey;
@implementation UIButton (block)
- (void)touchWithEvents:(UIControlEvents)controlEvents withBlock:(TouchBlock)touchBlock {
//通過一個(gè)key綁定block到相對(duì)應(yīng)的button
objc_setAssociatedObject(self, TouchKey, touchBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
//在這里添加action
[self addTarget:self action:@selector(buttonClick:) forControlEvents:(controlEvents)];
}
- (void)buttonClick:(UIButton *)sender {
// 通過key獲取到對(duì)應(yīng)button的block回調(diào)
TouchBlock touchblock = objc_getAssociatedObject(sender, TouchKey);
if (touchblock) {
touchblock(sender);
}
}
@end
使用
UIButton *button = [UIButton buttonWithType:(UIButtonTypeCustom)];
button.frame = CGRectMake(0, 0, 100, 50);
button.center = self.view.center;
button.backgroundColor = [UIColor redColor];
button.tag = 10001;
[button touchWithEvents:(UIControlEventTouchUpInside) withBlock:^(UIButton *sender) {
NSLog(@"sender.tag === %ld",(long)sender.tag);
}];
[self.view addSubview:button];
只用UIButton做了一個(gè)例子屋群,通過它的繼承關(guān)系可以看出控件很多都可以添加block來回調(diào)做出事件的處理闸婴。底下用View來做出一個(gè)類似button的功能控件來說明target-action核心機(jī)制:
//
// Test_Button.h
// RuntimeTest
//
// Created by Hongfei Zhai on 2017/11/22.
// Copyright ? 2017年 Hongfei Zhai. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef enum customButtonType{
customButtonTypeTouchDown,//按下響應(yīng)
customButtonTypeTouchUpInside//抬起響應(yīng)
}customButtonType;
@interface Test_Button : UIView
- (void)addTarget:(nonnull id)target action:(nonnull SEL)action events:(customButtonType)eventsType;
@end
//
// Test_Button.m
// RuntimeTest
//
// Created by Hongfei Zhai on 2017/11/22.
// Copyright ? 2017年 Hongfei Zhai. All rights reserved.
//
#import "Test_Button.h"
@interface Test_Button ()
{
id myTarget;//執(zhí)行按鈕回調(diào)方法的對(duì)象
SEL myAction;//按鈕的回調(diào)方法
}
@property (nonatomic,assign) customButtonType btnType;//觸發(fā)按鈕回調(diào)方法的枚舉值
@end
@implementation Test_Button
//添加點(diǎn)擊事件的方法
- (void)addTarget:(id)target action:(nonnull SEL)action events:(customButtonType)eventsType{
self.btnType = eventsType;
myTarget = target;
myAction = action;
}
//手指觸碰按鈕,調(diào)用此方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//調(diào)用按鈕的type為touchDown的時(shí)候在調(diào)用按鈕的回調(diào)方法芍躏,如果不是邪乍,就不能調(diào)用按鈕的回調(diào)
if (self.btnType == customButtonTypeTouchDown) {
//調(diào)用按鈕的回調(diào)方法 目標(biāo)動(dòng)作機(jī)制的核心 object - 回調(diào)方法的參數(shù)
[myTarget performSelector:myAction withObject:self];
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (self.btnType == customButtonTypeTouchUpInside) {
//調(diào)用按鈕的回調(diào)方法 目標(biāo)動(dòng)作機(jī)制的核心 object - 回調(diào)方法的參數(shù)
[myTarget performSelector:myAction withObject:self];
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
}
@end
用過BlocksKit都知道其中給控件添加block回調(diào)的機(jī)制也是通過runtime來實(shí)現(xiàn)的
當(dāng)然BlocksKit功能強(qiáng)大的多,邏輯也更加縝密纸肉,原理還是這個(gè)原理溺欧。而Runtime的使用會(huì)有出乎意料的幫助。