×

小窥 iOS 中的 Target-Action 设计模式

96
萌面大道
2016.11.02 17:57* 字数 650

Design Pattern in iOS

  • Info:
    • macOS 10.12.1
    • Xcode 8.2 Beta 1
    • Swift 3.0

前言

在前两天学习 iOS 中的 UISlider 控件时,看到官方文档提到,Slider 使用了 Target-Action 设计模式。即当用户移动滑块,将通知应用。同理,UIButton 也使用了该设计模式。那么,我们能从这个设计模式中学到什么呢?

Target-Action

Target-Action,意为 目标-行为,行为即要调用的方法,目标即消息的接收对象(Objective-C 语言使用消息机制,类似但不同于方法调用,该两种概念可能未来会进行探讨)。整个过程为:用户点击按钮,触发某事件发生,该消息由按钮传到另外的接收对象,接收对象再做相应处理。接收对象可以为任何对象,但通常为控制器(Controller)。

Responder Chain

在有关于 Target-Action 的官方文档章节中,提到了通过设置 Target 为 nil 来使用响应链。这样可以使得在运行时(Runtime)决定 Target 对象。关于此的探讨可以参照 Dominik Hauser 的 Utilize The Responder Chain For Target-Action 一文。

但是鉴于个人能力有限,而且在其原文中,作者新加了这么一句话:


Utilize The Responder Chain For Target-Action

显然,作者虽然了解响应链的存在,但不会去使用。

Demo

Interface Builder

通过 Interface Builder 可以拖线来实现(注意 Connection 选择 Action)。


Action

之后便可以在其内部进行其他操作。

@IBAction func buttonClick(_ sender: Any) {
    // do something...
}

当然,也可以先定义方法,再拖线,这样也是允许的。

Code

通过代码进行绑定 Target,可以先采用将控件拖线至代码中,这时 Connection 选择 Outlet。纯代码可以无视拖线。


Outlet

之后便可以通过 addTarget(_:action:for:) 来绑定 Target 和 Action。


addTarget(_:action:for:)
override func viewDidLoad() {
    super.viewDidLoad()

    demoButton.addTarget(self,
                         action: #selector(demoFunc),
                         for: .touchUpInside)
}

func demoFunc() {
    // do something...
}

#selector()

据考证,#selector() 是 Swift 2.2 中新增的写法。使得选择方法更加安全,因为 IDE 可以自动提示自动补全,即可在编译时刻检查。


Selector 结构体

#selector() 在 Swift 中为 Selector 结构体类型,但其本质是 Objective-C 的运行时概念。如果有方法为 private,则需要在方法前加上 @objc 才能运行正常。

override func viewDidLoad() {
    super.viewDidLoad()
    let selectorStruct = #selector(demoFunc)

    demoButton.addTarget(self,
                         action: selectorStruct,
                         for: .touchUpInside)
}

@objc private func demoFunc() {
    // do something...
}

关于 Selector 也可以参考喵神的文章,所有本文提及的文章均在参考资料中列出。

参考资料

Target-Action
Target-Action
Utilize The Responder Chain For Target-Action
在 Target-Action 中使用响应链
SELECTOR

[iOS]
Web note ad 1