iPhone中的响应者链是如何工作的?什么是“下一个响应者”?

32

这是文档中的说明:

如果第一个响应者[对事件或操作消息]无法处理事件或操作消息,则将其转发到称为响应者链的链接系列中的“下一个响应者”。响应器链允许响应器对象将处理事件或操作消息的责任转移给应用程序中的其他对象。

如果响应者链中的对象无法处理事件或操作,则它会将消息重新发送到链中的下一个响应者。该消息沿着链向高级别对象传递,直到被处理。如果未处理,则应用程序会将其丢弃。

那么下一个响应者是什么呢?

它是父视图吗?在它后面的视图吗?iOS如何决定第一响应者和第二响应者?

回答:
下一个响应者可以是该视图的父视图,也可以是传递给该视图的任何对象,如手势识别器或其他自定义对象。 iOS使用以下算法来确定下一个响应者:
1. 如果该视图是一个UIControl子类(例如UIButton或UITextField),则下一个响应者通常是它的委托对象。 这是因为UIControl子类通常将用户输入转发给其委托对象进行处理。
2. 如果该视图是UIViewController的子类,则下一个响应者通常是该视图控制器的父视图控制器或导航控制器。
3. 否则,下一个响应者可以是该视图的nextResponder属性指向的任何对象。 默认情况下,该属性指向视图的父视图,但是您可以通过覆盖该方法来更改此行为 UIResponder类的nextResponder方法。
因此,第一响应者是接收用户输入的第一个响应者。 在iOS中,当用户点击文本字段或键盘时,该文本字段将成为第一响应者,并且发送给它的任何操作消息都将由该文本字段处理。 第二个响应者是响应链中的下一个对象,如果第一个响应者无法处理事件或操作,则该对象将尝试处理它。
5个回答

34

First Responder是Cocoa中非常特定的概念。只有在文本字段获得焦点时,iOS才会决定设置First Responder。在其他所有时候,您必须明确控制要成为第一响应者的对象(请参见-canBecomeFirstResponder,-becomeFirstResponder)。

没有所谓的第二响应者。

所有响应者都有一个NextResponder(可以为nil)。这意味着从任何响应者开始,可能会沿着(但也可能不会沿着)响应者链(responder -> nextResponder -> nextResponder -> 等等)传递事件,直到处理完毕。

默认的响应者链包括view->superview->superview,但还可能包括UIViewControllers、UIWindows、UIWindowControllers、UIApplication等等,因此它严重依赖于您的对象层次结构(不仅仅是视图层次结构 - 所以不,您不能说nextResponder总是父视图)。在OSX 10.6中,针对不同类型的事件和操作,默认的链甚至对于不同的操作类型也是不同的,甚至可能包括您的应用程序委托(可能是或可能不是响应者),但我不确定这在iOS中是否适用。

默认链只是默认值,因此在管理完First Responder之后,您需要插入、删除和追加项到其响应者链中,以实现您所需的目标。

响应者链非常重要和复杂,您应该花时间阅读苹果文档相关内容。


19

根据nextResponder的文档:

UIResponder类不会自动存储或设置下一个响应者,而是默认返回nil。子类必须重写此方法来设置下一个响应者。UIView通过返回管理它的UIViewController对象(如果有)或其superview(如果没有)来实现此方法; UIViewController通过返回其视图的superview来实现该方法;UIWindow返回应用程序对象;UIApplication返回nil。


6

应用程序使用响应器对象接收和处理事件。

响应器对象是UIResponder类的任何实例,

  • 常见的子类包括

    UIView,UIViewController和UIApplication

响应器接收原始事件数据并必须处理事件或将其转发给另一个响应器对象。

当您的应用程序接收到事件时,UIKit会自动将该事件定向到

  • 最合适的响应器对象,称为

    第一响应者。

未处理的事件从活动响应器链中的响应器传递到响应器,

这是您的应用程序响应器对象的动态配置。

现在看下面的屏幕截图,还要考虑前面的视图层次结构:

img

UIbutton/UITextField --(nextResponder)-> UIView --(nextResponder)-> UIViewController

--(nextResponder)-> UIWindow --(nextResponder)-> UIApplication --(nextResponder)-> UIApplicationDelegate

这就是 iOS 上 Responder 链的工作原理,希望对任何人有所帮助。此外,苹果网站上最新的文章是 --> 链接(非常易懂)。


5
任何事件的响应链是:

UIView -> ViewController -> Window-> App Delegate

运行以下代码以更好地理解。

//
//  AppDelegate.swift
//  ResponderChain
//
//  Created by Ankit on 02/09/17.
//  Copyright © 2017 Ankit. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

   override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("App Delegate touch began")
    }


}



//
//  ViewController.swift
//  ResponderChain
//
//  Created by Ankit on 02/09/17.
//  Copyright © 2017 Ankit. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("ViewController touch Began")
        next?.touchesBegan(touches, with: event)
    }


}

extension UIWindow{
    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("Window Touch Began")
        next?.touchesBegan(touches, with: event)
    }
}
extension UIView{
    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("UIView touch Began")
        next?.touchesBegan(touches, with: event)
    }
}

2
响应者链是一系列链接的响应者对象。它从第一个响应者开始,并以应用程序对象结束。如果第一个响应者无法处理事件,则将事件转发给响应者链中的下一个响应者。
响应者对象是可以响应和处理事件的对象。UIResponder类是所有响应器对象的基类,它不仅定义了事件处理的编程接口,还定义了常见的响应器行为。UIApplication、UIViewController和UIView类的实例都是响应器,这意味着所有视图和大多数关键控制器对象都是响应器。请注意,核心动画层不是响应器。
第一个响应者被指定为首先接收事件的对象。通常,第一个响应者是一个视图对象。一个对象成为第一个响应者需要完成两件事:
Overriding the canBecomeFirstResponder method to return YES.

Receiving a becomeFirstResponder message. If necessary, an object can send itself this message.

请参考苹果文档以获取更详细的解释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接