您正在寻找的是一个内部类(不一定是匿名的),在一个范围内声明,允许它访问 MyClass 实例的 count 变量,并采用在不同的地方定义的协议范围。现在 Swift 有一些这样的部分,但看起来你不能以任何你想要的那样简洁的方式把它们放在一起。
你可能会考虑声明一个内部类:
class MyView: UIView {
let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
var count = 0 // type Int is inferred
class Helper: SomeProtocol {
func a0() { count-- } // ERROR
// ...
}
init() {
someComponent.delegate = Helper()
}
}
但这行不通,因为count 隐含地是self.count,其中self 是Helper 实例,而不是“拥有”Helper 实例的MyView 实例。而且没有办法从Helper 的方法中引用MyView 实例(或其属性),因为您也可以在没有现有MyView 实例的情况下构造MyView.Helper()。 Swift 中的内部类(或一般的嵌套类型)仅嵌套在词法范围内,而不嵌套在存在所有权中。 (或者换一种说法,因为您引用了 Java:Swift 中的所有内部类都类似于 Java 中的静态内部类。没有非静态内部类。)不过,如果这是您想要的功能,it's probably worth telling Apple you want it。
您也可以尝试在 MyView.init() 中声明 Helper -- 在 Swift 中,您可以在任何地方嵌套类型定义,包括内部函数或其他类型的方法。在那里定义,它可以引用MyView的属性。但是,现在Helper 的类型信息只在MyView.init() 内部可见,所以当你将它分配给someComponent.delegate(其类型只是SomeProtocol)时,你不能使用它......这个甚至使编译器崩溃。 (这是另一个bug to report,但很难说这个错误是真的“编译器在有效使用时崩溃”还是“代码不好,但编译器崩溃而不是产生错误”。)
我能想到的最接近的解决方案如下所示:
class SomeInnerComponent {
var delegate: SomeProtocol?
}
protocol SomeProtocol {
func a0()
func a1()
}
class MyClass {
var someComponent = SomeInnerComponent()
var count = 0
struct Helper: SomeProtocol {
var dec: () -> ()
var inc: () -> ()
func a0() { dec() }
func a1() { inc() }
}
init() {
someComponent.delegate = Helper(
dec: { self.count -= 1 }, // see note below
inc: { self.count += 1 }
)
}
}
它是如何工作的:
-
Helper 是一个内部结构(可以是一个类,但结构更简单)
- 实现了
a0和a1方法,满足SomeProtocol的要求
-
a0 和 a1 的实现调用闭包 dec 和 inc,它们是 Helper 结构的存储属性(也称为实例变量)
- 在构造
Helper 实例时编写(或以其他方式指定)这些闭包(使用默认的成员初始化器 Helper(dec: (Void -> Void), inc: (Void -> Void)))
- 因为您可以在初始化
Helper 时编写闭包,所以这些闭包可以在您调用初始化程序的位置捕获变量,包括引用MyClass 实例的隐式self 创建Helper。
您需要a0/a1 和dec/inc,因为您需要闭包(后者)而不是方法来捕获封闭状态。即使闭包和函数/方法在许多方面是可互换的,你也不能通过将闭包分配给方法/函数名称来创建方法/函数实现。 (如果SomeProtocol 需要闭包属性而不是方法,那就另当别论了,但我假设SomeProtocol 不在你的控制之下。)
无论如何,这是一种您可能并不真正需要的大量样板和抽象层,因此可能值得研究其他方式来构建您的代码。
注意:我的示例使用闭包 { self.count -= 1 },您可能会期望 { self.count-- }。后者不起作用,因为这是一个有值的表达式,所以 Swift 会将它解释为闭包返回值的简写。然后它会抱怨你将一个() -> Int 闭包分配给一个需要() -> ()(又名Void -> Void)闭包的属性。改用 -= 1 可以解决此问题。