使用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
变量,其运行时类型等于传入的元类型类型值,因此我们只成功删除了指定类型的手势识别器。