使用Swift Generics识别子类可以使用自定义类,但不能使用UITapGestureRecognizer

我想在swift中做一些事情,但我无法弄清楚如何实现它,即删除给定类型的手势识别器,这是我的代码(和示例),我在Xcode 7 beta中使用swift 2.0 5:

我有3个inheritance自UITapGestureRecognizer的类

class GestureONE: UIGestureRecognizer { /*...*/ } class GestureTWO: UIGestureRecognizer { /*...*/ } class GestureTHREE: UIGestureRecognizer { /*...*/ } 

将它们添加到视图中

 var gesture1 = GestureONE() var gesture11 = GestureONE() var gesture2 = GestureTWO() var gesture22 = GestureTWO() var gesture222 = GestureTWO() var gesture3 = GestureTHREE() var myView = UIView() myView.addGestureRecognizer(gesture1) myView.addGestureRecognizer(gesture11) myView.addGestureRecognizer(gesture2) myView.addGestureRecognizer(gesture22) myView.addGestureRecognizer(gesture222) myView.addGestureRecognizer(gesture3) 

我打印对象:

 print(myView.gestureRecognizers!) // playground prints "[<__lldb_expr_224.TapONE: 0x7fab52c20b40; baseClass = UITapGestureRecognizer; state = Possible; view = >, <__lldb_expr_224.TapONE: 0x7fab52d21250; baseClass = UITapGestureRecognizer; state = Possible; view = >, <__lldb_expr_224.TapTWO: 0x7fab52d24a60; baseClass = UITapGestureRecognizer; state = Possible; view = >, <__lldb_expr_224.TapTWO: 0x7fab52c21130; baseClass = UITapGestureRecognizer; state = Possible; view = >, <__lldb_expr_224.TapTWO: 0x7fab52e13260; baseClass = UITapGestureRecognizer; state = Possible; view = >, <__lldb_expr_224.TapTHREE: 0x7fab52c21410; baseClass = UITapGestureRecognizer; state = Possible; view = >]" 

我使用通用function进行了此扩展

 extension UIView { func removeGestureRecognizers(type: T.Type) { if let gestures = self.gestureRecognizers { for gesture in gestures { if gesture is T { removeGestureRecognizer(gesture) } } } } } 

然后我用它

 myView.gestureRecognizers?.count // Prints 6 myView.removeGestureRecognizers(GestureTWO) myView.gestureRecognizers?.count // Prints 0 

删除所有手势D:

这是一个自定义类的实验

 //** TEST WITH ANIMALS*// class Animal { /*...*/ } class Dog: Animal { /*...*/ } class Cat: Animal { /*...*/ } class Hipo: Animal { /*...*/ } class Zoo { var animals = [Animal]() } var zoo = Zoo() var dog1 = Dog() var cat1 = Cat() var cat2 = Cat() var cat3 = Cat() var hipo1 = Hipo() var hipo2 = Hipo() zoo.animals.append(dog1) zoo.animals.append(cat1) zoo.animals.append(cat2) zoo.animals.append(cat3) zoo.animals.append(hipo1) zoo.animals.append(hipo2) print(zoo.animals) //playground prints "[Dog, Cat, Cat, Cat, Hipo, Hipo]" extension Zoo { func removeAnimalType(type: T.Type) { for (index, animal) in animals.enumerate() { if animal is T { animals.removeAtIndex(index) } } } } zoo.animals.count // prints 6 zoo.removeAnimalType(Cat) zoo.animals.count // prints 3 

它实际上删除了它应该的类:D

我对UIGestureRecognizer的遗漏是什么? 我最终得到了一个解决方法,使得一个没有generics(无聊)的函数像这样:

 extension UIView { func removeActionsTapGestureRecognizer() { if let gestures = self.gestureRecognizers { gestures.map({ if $0 is ActionsTapGestureRecognizer { self.removeGestureRecognizer($0) } }) } } } 

这当然有效,但我仍然希望有一个真正的解决方案

我感谢您的帮助!!

注意:我在这里问的第一个问题

TL; DR:

使用dynamicType根据type参数检查每个手势识别器的运行时类型。


好问题。 看起来你遇到的情况是Objective-C的动态类型和Swift的静态类型之间的区别变得清晰。

在Swift中, SomeType.Type是类型的元类型类型,它实质上允许您指定编译时类型参数。 但这可能与运行时的类型不同。

 class BaseClass { ... } class SubClass: BaseClass { ... } let object: BaseClass = SubClass() 

在上面的示例中, object的编译时类是BaseClass ,但在运行时,它是SubClass 。 您可以使用dynamicType检查运行时类:

 print(object.dynamicType) // prints "SubClass" 

那为什么重要呢? 正如您在Animal测试中看到的那样,事情表现得如您所愿:您的方法采用的类型是Animal子类的元类型类型的参数,然后您只删除符合该类型的动物。 编译器知道T可以是Animal任何特定子类。 但是如果你指定了一个Objective-C类型( UIGestureRecognizer ),那么编译器会将它的脚趾浸入到Objective-C动态类型的不确定世界中,并且在运行时之前事情变得不那么可预测。

我必须警告你,我对这里的细节有点狡猾……我不知道编译器/运行时在混合Swift和Objective-C的世界时如何处理generics的细节。 或许有一些对这个主题有更好了解的人可以填写并阐明!

作为比较,让我们快速尝试一下您的方法的变体,其中编译器可以进一步明确Objective-C世界:

 class SwiftGesture: UIGestureRecognizer {} class GestureONE: SwiftGesture {} class GestureTWO: SwiftGesture {} class GestureTHREE: SwiftGesture {} extension UIView { func removeGestureRecognizersOfType(type: T.Type) { guard let gestureRecognizers = self.gestureRecognizers else { return } for case let gesture as T in gestureRecognizers { self.removeGestureRecognizer(gesture) } } } myView.removeGestureRecognizers(GestureTWO) 

使用上面的代码,只会删除GestureTWO实例,这就是我们想要的,如果仅适用于Swift类型。 Swift编译器可以查看此generics方法声明,而无需考虑Objective-C类型。

幸运的是,如上所述,Swift能够使用dynamicType检查对象的运行时类型。 有了这些知识,只需要稍微调整就可以使您的方法适用于Objective-C类型:

 func removeGestureRecognizersOfType(type: T.Type) { guard let gestureRecognizers = self.gestureRecognizers else { return } for case let gesture in gestureRecognizers where gesture.dynamicType == type { self.removeGestureRecognizer(gesture) } } 

for循环仅将手势识别器绑定到gesture变量,其运行时类型等于传入的元类型类型值,因此我们只成功删除了指定类型的手势识别器。