iOS中的设计模式之代理模式

什么是代理

简单的理解,有A和B两人,A想买饭,但是不想自己动手,让B去买。A每次买饭,直接跟B说,我要吃饭,B就去买回来了。
上述中,A,B指代2个对象,而吃饭代指行为(也就是方法)
如下图:



用代码来说明,就是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A {

var b: B!

init () {
b = B()
}

func A_buySomeFood() {
b.B_buySomeFood()
}
}

class B {

func B_buySomeFood() {
print("B去楼下买了2L可乐和3个面包,准备发酵。")
}
}



调用:

1
2
let a = A()
a.A_buySomeFood()



输出:

1
B去楼下买了2L可乐和3个面包,准备发酵。



就这么简单?对,就这么简单。
但是这么写有个问题,A直接持有了一个B对象,耦合度爆炸。
解决方案呢,就是用协议,有的语言叫接口,差不多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class A {

var b: B_delegate!

init () {
b = B()
}

func A_buySomeFood() {
b.B_buySomeFood()
}
}


protocol B_delegate {
func B_buySomeFood ()
}

class B: B_delegate {

func B_buySomeFood() {
print("B去楼下买了2L可乐和3个面包,准备发酵。")
}
}

这样似乎就好了不少,有人会问,你这不还是创建了个B么?错,我创建的是一个代理,一个任何遵守B_delegate协议的代理。它可以是C,D,E。。。
只要他遵守B_delegate。

引申

可以做到更好么?可以。
swift里,有个神奇的叫做协议扩展的东西(虽然很多其他语言也有),于是,你可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protocol B_delegate {
func B_buySomeFood ()
}

extension B_delegate {
func B_buySomeFood() {
print("B去楼下买了2L可乐和3个面包,准备发酵。")
}
}
class A {

init () {

}

func A_buySomeFood() {
self.B_buySomeFood()
}
}

一脸懵逼,有木有,这什么鬼?


但是还是有点不对,这个我们iOS里的代理有点不像啊?

代理在iOS中的应用

目前来说我感觉,比较常用的只有2个地方。

按钮点击事件传递

超级常见,代码如下:
cell里的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protocol MLTableViewCellDelegate:NSObjectProtocol {
func touchAvatar(btn:UIButton)
func reply(btn:UIButton)
}

class MLTableViewCell: UITableViewCell {

var avatarBtn: UIButton!
var replyBtn: UIButton!
weak var delegate:MLTableViewCellDelegate?

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
avatarBtn = UIButton(type: .Custom)
avatarBtn.addTarget(self, action: "touchAvatar:", forControlEvents: .TouchUpInside)

...

}

func touchAvatar(btn: UIButton) {
delegate?.touchAvatar(btn)
}

func reply(btn: UIButton) {
delegate?.reply(btn)
}



VC里的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class EditerTwoViewController: UITableViewDataSource, UITableViewDelegate, MLTableViewCellDelegate {

var tableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView()

...

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MLTableViewCell
cell.delegate = self
return cell
}

//delegate method
func reply(btn: UIButton) {

...

}

func touchAvatar(btn: UIButton) {

...

}



在这里VC是B,而cell是A。而不同的地方呢?就是多了一个weak。
为什么会有weak?这就是一个关于循环引用的典型问题。
因为swift中都是ARC,现在VC持有tableview,所以tableview+1s;而tableview持有cell,那么cell+1s;但是现在cell需要持有一个实现cellDelegate协议的东西,巧的是这个VC刚好就是实现了cellDelegate的东西。于是VC也+1s,最终形成铁三角。。

所以,我们要打破它,就需要使用weak关键字来虚化cell到VC这条线。

VC之间的反向传值

这个和上面的思路是一样的,不过这次是VC与VC之间循环引用。就不展开说了,留给读者自行体会。