使用运行时指定的协议一致性测试的通用调度机制&选择

时间:2016-08-18 21:52:49

标签: swift recursion selector swift-protocols

所以,我正在制作一个SpriteKit游戏,我想转发updatemouseDownkeyDown等...在GameScene上调用的事件,对于该场景的孩子,只要他们是具有适当响应者的SKNode的自定义子类。

我根据每个节点上要调用的函数制作了几个协议,就像我对需要接收KeyboardDelegatekeyDown等节点的keyUp一样......对于UpdateDelegateupdate等等didSimulatePhysics {...}对于每种类型的通话,总共有UpdateDelegateKeyboardDelegate,{{1} }}和MouseDelegate各自为其各自的调用类型。

所以CollisionDelegate我的功能如下:

GameScene

问题在于我要转发大约20个这样的事件,并且每个函数都有相同的代码,唯一不同的部分是func someEvent(someParameter: ArgumentType) { for child in children where child is SomeProtocol { //onSomeEvent should be required by SomeProtocol (child as! SomeProtocol).onSomeEvent(someParameter) } } SomeProtocol

我尝试创建一个处理所有这些的函数,所以我不需要为我想要转发的每个事件编写代码:

onSomeEvent

扩展程序在SKNode上,因此我可以在接收呼叫的每个单独节点的每个子节点上转发呼叫,无论它们是什么类型的SKNode。

函数本身似乎不太正确,并不是因为它不起作用,我无法在不使用extension SKNode { func forward<T>(method: Selector, onChildrenOfType: T.Type, withArgument argument: AnyObject) { for child in children where child is T { child.performSelector(method, withObject: first) } } } 的情况下直接传递协议,每当我这样调用它时:

SomeProtocol.self

我得到一个override func someEvent(someParameter: ArgumentType) { self.recurse(#selector(onSomeEvent(_:)), onChildrenOfType: SomeProtocol.self, withArgument: someParameter) } ,我假设因为编译器不知道在哪里寻找use of unresolved identifier 'onSomeEvent'函数。

所以...有没有办法使这项工作(除了可能使用旧的选择器语法),最好是我可以传递更多的2个参数(因为performSelector只允许最多2个,onSomeEventobjc_msgSend不可用),或者我应该坚持在我想要转发的每个事件中复制代码。

1 个答案:

答案 0 :(得分:2)

所以这很有趣&amp;相当棘手。关键是测试作为参数传入的运行时 - 协议类型 - 这是相当元,而在Swift中不可能使用编译时一致性检查来提高效率&amp;安全。首先,您需要将Obj-C运行时中的所有内容都置于基础,此处的关键是conformsToProtocol方法。如果您需要这样一个高度通用的调度,我不会尝试传递超过2个参数:而是传递某种容器(如NSNotification&#39; s userInfo: NSDictionary)和您需要的值。通过使用withObject:的{​​{1}}变体,我可以很容易地将以下内容调整为带有1个参数的函数,因为我确定您知道。请注意,选择器函数必须返回一个对象,否则您的代码会崩溃,所以我只是为了方便而选择了performSelector:(和可链接性!)

self

就递归而言,这是最简单的部分,与导航类型微积分或Foundation API无关。您只需在import Foundation // performSelector methods must return a reference to something @objc protocol P1 { func doP1Action() -> P1 } @objc protocol P2 { func doP2Action() -> P2 } class C1a: NSObject, P1 { func doP1Action() -> P1 { print("I'm doing C1a's impl of a P1 Action"); return self } } class C1b: NSObject, P1 { func doP1Action() -> P1 { print("I'm doing C1b's impl of a P1 Action"); return self } } class C2a: NSObject, P2 { func doP2Action() -> P2 { print("I'm doing C2a's impl of a P2 Action"); return self } } class C2b: NSObject, P2 { func doP2Action() -> P2 { print("I'm doing C2b's impl of a P2 Action"); return self } } var children = [ C1a(), C2b(), C1b(), C1a(), C2a() ] func performAction(action: Selector, forObjectsConformingTo conform: Protocol, inArray array: [AnyObject]) -> [AnyObject] { return array.flatMap { $0.conformsToProtocol(conform) ? $0.performSelector(action).takeRetainedValue() : nil } } // And now the fully generic reusable logic: print("Performing actions on P1's:") performAction(#selector(P1.doP1Action), forObjectsConformingTo: P1.self, inArray: children) print("Performing actions on P2's:") performAction(#selector(P2.doP2Action), forObjectsConformingTo: P2.self, inArray: children) //Performing actions on P1's: //I'm doing C1a's impl of a P1 Action //I'm doing C1b's impl of a P1 Action //I'm doing C1a's impl of a P1 Action //Performing actions on P2's: //I'm doing C2b's impl of a P2 Action //I'm doing C2a's impl of a P2 Action 上为forEach的子项发送递归调用。