父类和子类之间的弱引用



我们是否可以像下面的代码那样在类之间进行通信,而不是使用委托/协议模式和通知。我还没有见过这样的代码示例。但只是想知道为什么这应该有效或无效。

class Class1 {
var class2Obj: Class2 = Class2()
init() {
class2Obj.class1Obj = self
}
func class1Method() {
print("Parent")
}
}
class Class2 {
weak var class1Obj: Class1?
func class2Method() {
class1Obj.class1Method()
}
}

这里的委托模式。您的委托属性仅称为class1Obj,而不是更常用的delegate名称。这里的关键问题是您没有使用协议,因此这两个类是"紧密耦合的",即Class2高度依赖于Class1实现的细节。此外,对于这两个紧密耦合的类,还不清楚Class2可能需要Class1的哪些方法。这使得Class1的维护变得更加困难,因为很容易意外地做出破坏Class2行为的更改。这也使得Class2很难与Class1以外的其他类一起使用。

相反,您通常会声明一个协议来精确地阐明Class2和其他可能需要使用它的对象之间的契约的性质。结果是类的耦合不那么紧密,即Class2除了对所讨论的协议的一致性之外,不需要知道其他类的任何信息。此外,在编辑Class1时,如果您声明它符合协议,那么当您未能实现某些所需的方法或属性时,编译器将向您发出警告。

因此,只需少量的前期工作,该协议就可以使代码更容易维护。它还提供了一些额外的灵活性,您可以在将来将Class2Class1以外的东西结合使用。

最重要的是,协议可以产生更容易维护、更灵活、没有隐藏假设的代码。


如果您不想使用委托协议模式,另一种选择是使用闭包,其中Class1提供Class2可以调用的代码块。所以你可以做一些类似的事情:

class Class1 {
var class2Obj = Class2()
init() {
class2Obj.handler = { [weak self] in     // note `weak` reference which avoids strong reference cycle
self?.class1Method()
}
}
func class1Method() {
print("Parent")
}
}
class Class2 {
var handler: (() -> Void)?
func class2Method() {
handler?()
}
}

当您在两个类之间有一个丰富的接口时,委托协议模式很有用,而当您在这两个类间有一个非常简单的接口时这种闭包模式很有用。

坦率地说,上述更常见的排列是闭包与Class1Class2中发起的某个特定请求更直接地关联。因此,您可以将参数设置为Class2中适当方法的闭包。此外,您经常将数据传回,因此假设我们传回一个可选的String:

class Class1 {
var class2Obj = Class2()
func performClass2Method() {
class2Obj.class2Method { string in
guard let string = string else { return }
self.class1Method()
}
}
func class1Method() {
print("Parent")
}
}
class Class2 {
func class2Method(completionHandler: @escaping (String?) -> Void) {
// do something which creates `string`
// when done, call the closure, passing that `string` value back
completionHandler(string)
}
}

这些闭包模式是在对象之间进行简单接口的好方法,但也使两个类保持非常松散的耦合(即Class2Class1没有依赖关系),就像在委托模式中使用协议一样。但希望上面的闭包示例能够说明富委托协议模式的简单替代方案。

最新更新