假设您创建了两个视图控制器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中触发?我在文档中看到,如果你不打电话,你必须覆盖所有触摸方法,但我仍然不明白为什么这里有必要。
答案 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()被正确调用。