响应者链 - touchesMoved与touchesBegan的不同行为?

时间:2017-03-31 06:28:30

标签: ios swift

假设您创建了两个视图控制器A和B. A有一个segue到B(具体来说,我认为这里不重要,因为结果似乎是相同的。我将使用push作为示例。 )。 A具有以下实现:

class A: UIViewController {

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      print("A received a begin touch")
  }
  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      print("A received a move touch")
  }
}

在B中,你有:

class B: UIViewController {

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      print("B received a begin touch")
  }
}

这将阻止进入ViewController A的所有触摸。即使有触摸移动,A也不会接收它。

但是,如果B的代码是:

class B: UIViewController {

  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      print("B received a move touch")
  }
}

然后A的“开始触摸”打印,A和B的“移动触摸”打印。总而言之,当在B类中实现touchesBegan时,打印到控制台的唯一事情是“B接收到开始触摸”。当在B类中仅实现touchesMoved时,控制台打印“A收到开始触摸”,然后是接收移动触摸的A和B的交替模式。

那么这种差异的原因是什么?为什么touchesBegan在B中覆盖会阻止touchesMoved方法在A中触发?为什么B中的touchesMoved方法不能阻止touchesMoved方法在A中触发?我在文档中看到,如果你不打电话,你必须覆盖所有触摸方法,但我仍然不明白为什么这里有必要。

2 个答案:

答案 0 :(得分:1)

这就是响应者链的工作方式。它与var view = self while (!view.respondsToSelector(#selector(touchesBegan...)) { view = view.superview } view.touchesBegan(...) 个对象的作用相同。如果你有一个按钮B作为按钮A的子视图,那么如果你点击按钮B的区域,它会触摸而不是按钮A.按钮A没有注册按钮。

显然Apple的实现类似于

touchesBegan

Apple文档还说明了{{1}}:

  

如果在不调用super(常用模式)的情况下覆盖此方法,则还必须覆盖其他方法来处理触摸事件,即使您的实现不执行任何操作。

这意味着只实现一种方法会产生不确定的结果。

答案 1 :(得分:1)

经过调查,我想我可能会做些什么。

我已经创建了一个Xcode项目,让您的示例投入使用,使用UIViewcontroller和UIViews ..来查看它的行为方式。然后我想重新创建相同的&#34;结果&#34;使用Swift模式我们都知道,好像我要实现UIViews / UIViewController响应链。我在下面添加了这些文件的链接。

最终行为是通过将子类+协议与标准实现相结合获得的,因此当事件链到达时,它会对您实现的方法产生影响。假设所有事件都通过名为stuff()的基金提供,并考虑以下因素。

enum State: Int {
    case None
    case Start
    case Doing
    case End
}

protocol StuffTouches {
    var superStuff: StuffTouches? {get set}
    var gesturingState: State {get set}
    func begin()
    func moves()
    func ended()
    mutating func stuff()
}

extension StuffTouches {
    mutating func stuff() {
        switch gesturingState {
        case .None:
            gesturingState = .Start
            print("Protocol \(self) BEGIN")
            begin()
        case .Start:
            gesturingState = .Doing
            print("Protocol \(self) Moves")
            moves()
        case .End:
            gesturingState = .None
            print("Protocol \(self) Ended")
            ended()
        case .Doing:
            print("Protocol \(self) Moves")
            moves()
        }
        if gesturingState == .None {
            gesturingState = .Start

        }

    }
    func moves() {
        print("Protocol \(self) Moves")
        superStuff?.moves()
    }
    func ended() {
        print("Protocol \(self) Ended")
        superStuff?.ended()
    }

}

class BaseStuff: StuffTouches {
    var superStuff: StuffTouches?
    var gesturingState: State = .None


    func begin() {
        print("Base \(self) BEGIN")
    }

    func moves() {
        print("Base \(self) Moves")
    }

    func ended() {
        print("Base \(self) Ended")
    }
}

class TypeCStuff: BaseStuff {
    override func moves() {
        print("C Moves")
    }
}

var stuff = TypeCStuff() as BaseStuff
stuff.superStuff = BaseStuff()
print("Event 1 - Touches begin")
stuff.stuff()
print("Event 2 - Continues")
stuff.stuff()
print("3")
stuff.stuff()
print("4")
stuff.stuff()
print("5")
stuff.stuff()

打印输出为:

Event 1 - Touches begin
Protocol __lldb_expr_7.TypeCStuff BEGIN
Base __lldb_expr_7.TypeCStuff BEGIN
Event 2 - Continues
Protocol __lldb_expr_7.TypeCStuff Moves
C Moves
3
Protocol __lldb_expr_7.TypeCStuff Moves
C Moves
4
Protocol __lldb_expr_7.TypeCStuff Moves
C Moves
5
Protocol __lldb_expr_7.TypeCStuff Moves
C Moves

它完全模仿您在所描述的事件中找到的行为。

为研究我创建了一个项目和一个游乐场,在github

上找到它们

回到最初的问题:我不确定什么是Responder实现,但我相信Apple要求您实现两者的原因之一是默认实现使用协议,扩展和子类的组合,如果你不覆盖所有方法,你可能会被切断,如下所示:

protocol ThisProtocol {

}

extension ThisProtocol {
    func test() {
        print("Protocol")
    }

    func someOtherMethods() {
        print("Protocol 2")
    }

    func ultimateTest() {
        test()
        someOtherMethods()
    }
}

struct ThisStruct: ThisProtocol {

    func test1() {
        test()
    }

    func test2() {
        ultimateTest()
    }

    func test() {
        print("ThisStruct")
        (self as ThisProtocol).test()
    }
}

ThisStruct().test2()

上面代码的输出是:

Protocol
Protocol 2

(尽管func test()是在ThisStruct中实现的)

如果你调用test1(),你会看到ThisStruct.test()被正确调用。