我目前正在一个主要是Objective-C的项目中编写一些Swift代码。在我们的ObjC代码中,我们有一个声明typedef GPUImageOutput<GPUImageInput> MyFilter;
的标头。然后我们可以宣布例如@property只能是实现GPUImageOutput
的{{1}}子类。
(注意:GPUImageInput
和GPUImageOutput
不是由我定义的;它们是GPUImage library的一部分
我们的Swift代码似乎没有认识到这一点,即使标头在我们的桥接头中是#imported。我试图在Swift中复制声明,但这些都不是正确的语法:
GPUImageInput
typealias MyFilter = GPUImageOutput, GPUImageInput
答案 0 :(得分:4)
你不能像那样声明类型。
我们能做的最好的事情就是这样:
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()
}
}
答案 1 :(得分:3)
在Swift 4中,您可以使用新的&amp; sign(下面是确认UIViewController和UITableViewDataSource的参数示例:
func foo(vc: UIViewController & UITableViewDataSource) {
// access UIViewController property
let view = vc.view
// call UITableViewDataSource method
let sections = vc.numberOfSectionsInTableView?(tableView)
}
答案 2 :(得分:1)
在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")
}
}
更新:现在我明白你在哪里/为何拥有这些类型...
GPUImage似乎有一个快速的例子可以做到你想要的,尽可能快速。
请参阅here:
class FilterOperation<FilterClass: GPUImageOutput where FilterClass: GPUImageInput>: FilterOperationInterface {
...
type constraint syntax也可以应用于函数,并使用where clause,这可能与您直接在Swift中获得的效果一样好。
我试图了解如何移植这个有点常见的objc转义,我越是意识到它是最快速的方式。一旦我在GPUImage本身看到了这个例子,我确信它至少是你的答案。 : - )
更新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
子句作为后卫的一个很好的例子(兼具良好的功能和Swift-ly)。但是,我只是讨厌在可计算属性存在时编写setFoo()
函数。然后,即使使用可计算属性也有代码味道,因为我们似乎无法将通用类型约束应用于set
,并且必须在线进行协议一致性测试。
答案 3 :(得分:-3)
您可以使用typealias
关键字。以下是如何做到这一点:
typealias MyNewType = MyExistingType
MyExistingType是协议还是函数或枚举无关紧要。它只需要某种类型。最好的部分是你可以对它应用访问控制。你可以说
private typealias MyNewType = MyExistingType
这使得MyNewType只能访问在。
中定义的上下文