假设您创建了两个 View Controller ,A 和 B。A 有一个 segue 到 B(我认为具体哪个 segue 在这里并不重要,因为结果似乎是相同的。我将使用 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 received a begin touch”,然后交替显示 A 和 B 都接收到移动触摸。
那么造成这种差异的原因是什么?为什么 touchesBegan 在 B 中覆盖会阻止 touchesMoved 方法在 A 中触发?为什么 B 中的 touchesMoved 方法不阻止 A 中的 touchesMoved 方法触发?我在文档中看到如果不调用 super 就必须覆盖所有触摸方法,但我仍然不明白为什么这里有必要这样做。
最佳答案
经过调查,我想我可能有所发现。
我已经创建了一个 Xcode 项目来将您的示例投入使用,同时使用 UIViewcontroller 和 UIViews.. 来查看它的行为方式。然后我想使用众所周知的 Swift 模式重新创建相同的“结果”,就好像我要实现 UIViews/UIViewController 响应者链一样。我在下面添加了指向这些文件的链接。
最终的行为是结合子类+协议(protocol)和标准实现得到的,所以当事件链到来时,你实现了哪些方法是有区别的。假设所有事件都是通过名为 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
它完全模拟了您在所描述的事件中发现的行为。
为了研究,我创建了一个项目和一个 Playground ,可以在 github 上找到它们
回到最初的问题:我不确定 Responder 实现是什么,但我相信 Apple 要求您同时实现两者的原因之一是默认实现使用协议(protocol)、扩展和子类的组合,如果您没有覆盖所有方法,您可能会被排除在链之外,如下所示:
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() 被正确调用。
关于ios - 响应链 - touchesMoved 与 touchesBegan 的不同行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43133860/
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio
RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。