响应者链条简单理解

133 阅读2分钟
import UIKit

class ViewController: UIViewController {
    
    func clickButton() {
        
        print("我被点击啦")
        
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
        
        view.addSubview(button)
        
        button.addTarget(self, action: "clickButton", forControlEvents: UIControlEvents.TouchUpInside)
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

首先我们可以看一下上面的代码,看起来是没错误的,也没有警告,运行起来也正常无误,但是,还是有点小问题的,如果在别的文件中,创建了一个ViewController的对象,那么那个对象是可以调用到clickButton()这个方法的.我们希望该方法作为一个内部方法,而不希望外界能够进行访问,那么我们可以这样写:

private func clickButton() { 
      print("我被点击啦")
 }

这里加上了private关键字之后,别的文件中确实不能通过ViewController的对象来调用此方法了,看起来像是解决了问题,但是运行的时候就报错了.

crash.png

报错的原因是不是很眼熟,调用了一个未知的方法.因为添加了private关键字,运行循环无法正确发送消息,找不到该方法,所以就崩掉了.那我们来看一下这个方法是如何干活的.

stack.png

我们在clickButton()内部打上断点,来看一下堆栈的调用. 首先从1开始看到程序开始运行,2.运行循环接到事件被唤醒,3.处理事件队列,4找到最合适的响应者,并且把让其处理事件. 然后我们看到UIViewController被作为最合适的响应者,去调用了clickButton()方法,但是前面有一个@objc. 因为在OC开发都是消息机制,动态给对象发送消息.Swift没有消息机制,所以,它前面添加一个@objc

总结:
1.iOS所有的事件都是运行循环来监听的,平时运行循环处于休眠状态,当有事件后,运行循环就醒了,开始处理事件.
2.UIApplication发送事件给UIWindow,UIWindow来找最合适的触摸事件响应者,一直找到ViewController,那么久由ViewController来执行该方法. 在写target-action模式的时候,我们需要在方法前面添加上private来使方法私有化,还需要在private之前添加@objc,来保证运行循环能够正确发送此消息,即使该方法被标记为private.

如有错误,还望指正. >.<