什么是声明`typedef SomeClass <SomeProtocol> MyType`的Swift等价物?

我目前正在写一些主要是Objective-C的项目中的Swift代码。 在我们的ObjC代码中,我们有一个头声明typedef GPUImageOutput<GPUImageInput> MyFilter; 。 然后我们可以声明一个GPUImageOutput ,它只能是实现GPUImageInputGPUImageOutput子类。

(注意: GPUImageOutputGPUImageInput不是我自己定义的;它们是GPUImage库的一部分)

我们的Swift代码似乎没有认识到这一点,即使头文件在我们的桥接头文件中是#import。 我试图在Swift中复制这个声明,但是这些都不是正确的语法:
typealias MyFilter = GPUImageOutput, GPUImageInput
typealias MyFilter = GPUImageOutput : GPUImageInput

在Swift 4中,你可以用new&sign来实现这个(下面是一个确认UIViewController和UITableViewDataSource参数的例子:

 func foo(vc: UIViewController & UITableViewDataSource) { // access UIViewController property let view = vc.view // call UITableViewDataSource method let sections = vc.numberOfSectionsInTableView?(tableView) } 

你不能像这样声明typealias。

我们能做的最好的是这样的:

 class MyClass { private var filter:GPUImageOutput init<FilterType:GPUImageOutput where FilterType:GPUImageInput>(filter:FilterType) { self.filter = filter } func setFilter<FilterType:GPUImageOutput where FilterType:GPUImageInput>(filter:FilterType) { self.filter = filter } func someMethod() { let output = self.filter let input = self.filter as GPUImageInput output.someOutputMethod() input.someInputMethod() } } 

在Swift中,类似下面的东西应该能够完成你的任务,但是它不同于ObjC的对应部分:

 typealias GPUImageOutput = UIImage @objc protocol GPUImageInput { func lotsOfInput() } class GPUImageOutputWithInput: GPUImageOutput, GPUImageInput { func lotsOfInput() { println("lotsOfInput") } } // ... var someGpuImage = GPUImageOutput() var specificGpuImage = GPUImageOutputWithInput() for image in [someGpuImage, specificGpuImage] { if let specificImage = image as? GPUImageInput { specificImage.lotsOfInput() } else { println("the less specific type") } } 

更新:现在,我明白你在哪里/为什么有这些types…

GPUImage似乎有一个快速的例子,尽可能快地做你想做的事情。

看到这里 :

 class FilterOperation<FilterClass: GPUImageOutput where FilterClass: GPUImageInput>: FilterOperationInterface { ... 

types约束语法也可以应用到函数中,并且使用where子句 ,这可能和你直接在Swift中得到的一样好。

我越想了解如何移植这个有点常见的objc trope,我越发现它是最快捷的方式。 一旦我在GPUImage中看到了这个例子,我确信这至less是你的答案。 🙂

更新2:因此,除了上面链接到使用Swift的特定GPUImage示例之外,我越来越多地考虑这个问题,要么使用where子句来守护setter函数,要么使用可计算属性来过滤set函数只有走的路。

我想出了这个策略:

 import Foundation @objc protocol SpecialProtocol { func special() } class MyClass {} class MyClassPlus: MyClass, SpecialProtocol { func special() { println("I'm special") } } class MyContainer { private var i: MyClass? var test: MyClass? { get { return self.i } set (newValue) { if newValue is SpecialProtocol { self.i = newValue } } } } var container = MyContainer() println("should be nil: \(container.test)") container.test = MyClass() println("should still be nil: \(container.test)") container.test = MyClassPlus() println("should be set: \(container.test)") (container.test as? MyClassPlus)?.special() 

输出:

 should be nil: nil should still be nil: nil should be set: Optional(main.MyClassPlus) I'm special 

(或者,你也可以使用precondition(newValue is SpecialProtocol, "newValue did not conform to SpecialProtocol")来代替is检查,但是如果不符合的话,那么assert()可能会崩溃应用程序。取决于你的需求。)

@ rintaro的答案是一个很好的答案,并且是使用where子句作为后卫的一个很好的例子(既有很好的function,也有Swift-ly)。 但是,我只是讨厌编写一个setFoo()函数时,可计算的属性存在。 再次,即使使用可计算属性也有代码味道,因为我们似乎无法将genericstypes约束应用于set ,而必须在线执行协议一致性testing。

你可以使用typealias关键字。 这里是如何做到这一点:

 typealias MyNewType = MyExistingType 

MyExistingType是协议还是函数还是枚举都没有关系。 所有它需要是某种types。 最好的部分是你可以应用访问控制。 你可以说

 private typealias MyNewType = MyExistingType 

这使得MyNewType只能访问在其中定义的上下文。