在写程序的时候,用了MVC将程序分层。那么就得在写程序的时候把对应的代码写在对应的层里。
target/action模式,就是用来解决这个问题的。也就是所谓的解耦合。程序里就应该做到“高聚合,低耦合”。
高聚合的意思,就是将属于自己的东西,都写在自己的层次里,尽量少的写在其他层次中。
低耦合的意思,是不同的层次之间,尽量少的关联,但不能不关联。
以下是target/action实现解耦合的流程:(只写关键代码)
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]]autorelease];
self.window.backgroundColor = [UIColor whiteColor];
RootViewController *root = [[RootViewController alloc]init];
self.window.rootViewController = root;
[self.window makeKeyAndVisible];
[root release];
root = nil;
return YES;
}
代理,将根视图设置为RootViewController的对象,不再使用自己的window。
RootViewController.m
#import "RootViewController.h"
#import "RootView.h"
#import "ButtonView.h"
#import "ColorView.h"
@interface RootViewController ()
@property(nonatomic,retain)RootView *rv;
@end
@implementation RootViewController
-(void)loadView{
self.rv = [[[RootView alloc]initWithFrame:[[UIScreen mainScreen] bounds]]autorelease];
self.view = _rv;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 告诉buttonView target 是谁,action是谁。
[self.rv.bv myAddTarget:self action:@selector(bvAction:)];
}
- (void)bvAction:(ButtonView *)sender{
NSLog(@"123456");
NSLog(@"%@",sender);
}
1、@property(nonatomic,retain)RootView *rv;将试图设置为试图控制器所对应的视图(也就是将RootView代替controller自己本身的视图self.view = _rv;)。
2、[self.rv.bv myAddTarget:self action:@selector(bvAction:)];
(1)rv为controller被替代的根视图
(2)bv是我们自己定义的一个视图(ButtonView)
(3)myAddTarget:self action:@selector(bvAction:)
是我们在ButtonView中定义的一个方法
(4)参数self是controller本身,将controller本身传过去
(5)参数@selector(bvAction:)是用方法选择器将bvAvtion方法传过去。
RootView.h
#import <UIKit/UIKit.h>
@class ButtonView;
@class ColorView;
@interface RootView : UIView
// bv 属性将要在controller中使用
@property(nonatomic,retain)ButtonView *bv;
@end
把视图ButtonView作为RootView的一个属性。
RootView.m
#import "RootView.h"
#import "ButtonView.h"
@implementation RootView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self p_setupView];
}
return self;
}
- (void)p_setupView{
self.backgroundColor = [UIColor yellowColor];
self.bv = [[[ButtonView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]autorelease];
self.bv.backgroundColor = [UIColor blueColor];
[self addSubview:_bv];
}
@end
根视图,就是把那些视图都加在这个rootView上 。
ButtonView.h
@font-face { font-family: "Courier New"; }@font-face { font-family: "宋体"; }@font-face { font-family: "Cambria Math"; }@font-face { font-family: "@宋体"; }@font-face { font-family: "Cambria"; }@font-face { font-family: "Heiti SC Light"; }@font-face { font-family: "@Heiti SC Light"; }p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; text-align: justify; font-size: 12pt; font-family: Cambria; }.MsoChpDefault { font-family: Cambria; }div.WordSection1 { page: WordSection1; }
#import <UIKit/UIKit.h>
@interface ButtonView : UIView{
// 目标实例变量
id _target;
// 事件实例变量
// 方法选择器类型
SEL _action;
}
// 添加目标和事件
- (void)myAddTarget:(id)target action:(SEL)action;
@end
1、我们自己定义的视图,定义了两个实例变量,target是id类型的,也就是能代表所有的类型,用来接收一个目标,这个目标是为了执行action中的方法的。action是用来接收传进来的我自己要实现的方法(这里是点击事件bvButtonAction)。
2、- (void)myAddTarget:(id)target action:(SEL)action;
声明一个方法用来把controller中的要执行action方法的对象,执行的方法action传进来。
ButtonView.m
#import "ButtonView.h"
@implementation ButtonView
// 添加目标和事件
- (void)myAddTarget:(id)target action:(SEL)action{
_target = target;
_action = action;
}
在我们真正 要布局的地方重写初始化方法,把对应的视图建出来。
注意,我们想实现的点击事件,不在这里,这里没有点击事件,因为点击事件是逻辑性的东西,就把它写在了控制器ViewController里。
具体流程如下:
1、从controller开始,重写loadView方法,把rootView初始化,并代替自己的视图(self.view),然后去到rootView中,在初始化rootView的时候,把ButtonView也初始化了,创建了一个ButtonView视图bv。
2、当把视图都创建完毕后,完成加载,会回到controller中,调用viewDidload方法。此时我们就要重写这个方法,在viewDidload方法里,我们写上
[self.rv.bv myAddTarget:self action:@selector(bvAction:)];
这个调用方法,也就是把Buttonview中声明的myAddTarget: action:方法放到这里来调用。就会把控制器自己和在控制器里定义的ButtonView的点击响应事件方法传回去给ButtonView。
3、在ButtonView中,就会完成两个实力变量_target 和_action赋值。
4、此时,viewDidload方法执行完毕,真正完成视图的加载。
5、点击视图时,触发touchesBegan方法,在这个方法里,
[_target performSelector:_action withObject:self];
这个才是我们真正让_target和 _action完成功能的语句。这个意思就是让_target
(这就是之前传进来了controler )去执行_action (也就是之前传进来的bvAction方法)self就是ButtonView自己,设置这个withObject的参数,就是为了controller中定义bvAction方法的时候,参数sender得到ButtonView对象。
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"开始点击..");
// 让target执行action方法
[_target performSelector:_action withObject:self];
}
@end