iOS的Target-Action模式传值的最佳方式

文章目录
  1. 给对象加tag
  2. 给父类做category

在iOS中,所有的UIControl标准控件使用到最普遍最传统的执行方法的方式就是Target-Action,中文一般称作目标-动作,是比较常用的一种设计模式。它的主要思想就是,在对象产生某个事件的特定时刻,给一个对象发送一个消息。就好像说『当talisk即将吃早饭的时候,swain去煎个蛋』。

其实Target-Action是很好用很方便的一个模式,但其最致命的一个缺点就是传值很麻烦,本文总结下这种模式的传值方式,并给出我认为最好的一个传值方式。

给对象加tag

这是最简单的一个方式,tag是一个无符号整型值,贯穿于所有UIKit控件,给控件加上tag,在action方法里可以取到sender,对sender做强制类型转换即可拿到tag

1
[self.datePicker addTarget:self action:@selector(dateChange:) forControlEvents:UIControlEventValueChanged];
1
2
3
4
5
- (void)dateChange:(id)sender {
if (((UIDatePicker *)sender).tag) {
NSLog(@"tag0");
}
}

由于tag是个无符号整型数值,也仅仅能传递一些简单数据。

sender就是发起行为的对象,就像上面这段代码所写,当datePicker的值发生变化的时候,调用selfdateChange:方法,这个方法默认参数就是sender

给父类做category

通过category给父类加上一些方法,使子类对象能够携带一些数据,这样对于开发者来说就很自由了。

1
2
3
4
5
6
7
#import <Foundation/Foundation.h>
@interface NSObject (Extension)
@property (nonatomic,retain)NSDictionary *userInfo;
@end

在头文件中,注明category和名称,加上我们需要使用的数据的property。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "NSObject+Extension.h"
#import <objc/runtime.h>
@implementation NSObject (Extension)
- (void)setUserInfo:(NSDictionary *)_userInfo {
objc_setAssociatedObject(self, @"userInfo", _userInfo, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)userInfo {
return objc_getAssociatedObject(self, @"userInfo");
}
@end

在实现文件中,要用到Objective-C的Runtime黑魔法了,通过使用objc_getAssociatedObjectobjc_setAssociatedObject两个运行时函数的使用,动态地向NSObject根类中添加了属性,这样,只要是继承自NSObject并且引用了这个Category的地方,我们都可以给对象添加userInfo这个属性,意味着我们想传递什么就可以传递什么了。

在写完这个Category后,我们在需要传值的地方,给对象设置好userInfo,即可。

1
2
[self.datePicker addTarget:self action:@selector(dateChange:) forControlEvents:UIControlEventValueChanged];
[self.datePicker setUserInfo:@{@"from": [NSDate date], @"to": [NSDate date]}];
1
2
3
- (void)dateChange:(id)sender {
NSLog(@"%@", ((UIDatePicker *)sender).userInfo);
}