Swift 泛型和协议不适用于 UIKit [可能的错误]
Swift Generics and Protocols not working on UIKit [possible bug]
TL;DR -> 滚动到底部
在尝试使用 Swift 在面向协议的编程中标记 Apple 时,我在尝试在 class 之间实现委托模式时偶然发现了以下问题。
我将从这个例子开始:
protocol PhotoHandlerParent {}
class UIViewController {}
class MyViewController: UIViewController, PhotoHandlerParent {}
class PhotoHandler: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var delegate: PhotoHandlerParent
}
到目前为止,还不错。 MyViewController
的一个实例将被愉快地指定为 PhotoHandler
的委托。但是假设我不仅希望委托对象符合 PhotoHandlerParent
,而且还符合 class UIViewController
。在此特定示例中,PhotoHandler
可以代表其父视图控制器呈现和关闭 UIImagePickerController
。很像:
protocol PhotoHandlerParent {}
class UIViewController {}
class MyViewController: UIViewController, PhotoHandlerParent {}
class PhotoHandler: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var delegate: UIViewController, PhotoHandlerParent
}
不幸的是,上面的代码不适用于 Swift。另一方面,Swift 确实有泛型,这在这种情况下可能会有所帮助。因此可以尝试:
protocol PhotoHandlerParent {}
class UIViewController {}
class MyViewController: UIViewController, PhotoHandlerParent {}
class PhotoHandler<Parent where Parent: UIViewController, Parent: PhotoHandlerParent>: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var delegate: Parent
}
现在有趣的是,MyViewController
的一个实例将返回并愉快地分配为 PhotoHandler
的委托。没有编译错误,没有运行时错误。但是...
TL;DR:问题
运行 sample code 对于这个问题,可以看到 class 的一个实例用泛型声明并设置为 UIImagePickerController
的委托是从来没有被它调用过。 没有 泛型的对象实例被 UIImagePickerController
.
调用
我最好的假设是编译器不会抱怨,因为它可以验证 PhotoHandler
是否符合 UIImagePickerControllerDelegate
。然而,在运行时,PhotoHandler
实例实际上是一个 PhotoHandler<MyViewController>
实例,因此以某种方式干扰了 UIImagePickerController
识别其委托实际实现其协议的能力。
还是我漏掉了什么?
干杯
从文档的角度来看,这是正确的行为,因为:
Method in a generic class cannot be represented in Objective-C
回复@Bell App Lab评论:
打开 this page 并向下滚动到 轻量级泛型 。注意事项:
Aside from than these Foundation collection classes, Objective-C
lightweight generics are ignored by Swift. Any other types using
lightweight generics are imported into Swift as if they were
unparameterized.
它基本上是说泛型 (ObjC -> Swift) 仅为 Foundation 集合导入 类 其余部分将被忽略 - IOW 导入时就好像它们没有参数化一样。
也许我们可以期待未来在这方面有所改进,但我对此表示怀疑。
TL;DR -> 滚动到底部
在尝试使用 Swift 在面向协议的编程中标记 Apple 时,我在尝试在 class 之间实现委托模式时偶然发现了以下问题。
我将从这个例子开始:
protocol PhotoHandlerParent {}
class UIViewController {}
class MyViewController: UIViewController, PhotoHandlerParent {}
class PhotoHandler: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var delegate: PhotoHandlerParent
}
到目前为止,还不错。 MyViewController
的一个实例将被愉快地指定为 PhotoHandler
的委托。但是假设我不仅希望委托对象符合 PhotoHandlerParent
,而且还符合 class UIViewController
。在此特定示例中,PhotoHandler
可以代表其父视图控制器呈现和关闭 UIImagePickerController
。很像:
protocol PhotoHandlerParent {}
class UIViewController {}
class MyViewController: UIViewController, PhotoHandlerParent {}
class PhotoHandler: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var delegate: UIViewController, PhotoHandlerParent
}
不幸的是,上面的代码不适用于 Swift。另一方面,Swift 确实有泛型,这在这种情况下可能会有所帮助。因此可以尝试:
protocol PhotoHandlerParent {}
class UIViewController {}
class MyViewController: UIViewController, PhotoHandlerParent {}
class PhotoHandler<Parent where Parent: UIViewController, Parent: PhotoHandlerParent>: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var delegate: Parent
}
现在有趣的是,MyViewController
的一个实例将返回并愉快地分配为 PhotoHandler
的委托。没有编译错误,没有运行时错误。但是...
TL;DR:问题
运行 sample code 对于这个问题,可以看到 class 的一个实例用泛型声明并设置为 UIImagePickerController
的委托是从来没有被它调用过。 没有 泛型的对象实例被 UIImagePickerController
.
我最好的假设是编译器不会抱怨,因为它可以验证 PhotoHandler
是否符合 UIImagePickerControllerDelegate
。然而,在运行时,PhotoHandler
实例实际上是一个 PhotoHandler<MyViewController>
实例,因此以某种方式干扰了 UIImagePickerController
识别其委托实际实现其协议的能力。
还是我漏掉了什么?
干杯
从文档的角度来看,这是正确的行为,因为:
Method in a generic class cannot be represented in Objective-C
回复@Bell App Lab评论:
打开 this page 并向下滚动到 轻量级泛型 。注意事项:
Aside from than these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.
它基本上是说泛型 (ObjC -> Swift) 仅为 Foundation 集合导入 类 其余部分将被忽略 - IOW 导入时就好像它们没有参数化一样。
也许我们可以期待未来在这方面有所改进,但我对此表示怀疑。