【问题标题】:Weak reference between parent and child classes父类和子类之间的弱引用
【发布时间】:2017-01-22 01:30:16
【问题描述】:

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

class Class1 {

    var class2Obj: Class2 = Class2()
    init() {
      class2Obj.class1Obj = self
    }

    func class1Method() {
       print("Parent")
    }
}

class Class2 {

   weak var class1Obj: Class1?

   func class2Method() {
      class1Obj.class1Method()
   }

}

【问题讨论】:

  • 是的,你可以这样交流。但是delegate、block和closure更容易让其他人理解Class2通过“方法”回调。这是一个“最佳实践是什么”的问题。:)
  • @YunCHEN - 是的,你也可以使用闭包模式。但我认为使用闭包是“最佳实践”的说法。像大多数设计选择一样,它比这更复杂。这真的取决于。在简单的情况下,闭包可能很有用。但在更丰富的接口中,委托协议模式通常更优越。这仅取决于接口的性质。但是,我同意 Anshu 的两个紧耦合类的模式不是最理想的。
  • @Rob,同意你的看法。

标签: ios swift memory-management


【解决方案1】:

你在这里所拥有的一个委托模式。您的委托属性仅称为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)
    }

}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-16
    • 2017-09-11
    • 1970-01-01
    • 2013-07-25
    • 2016-06-22
    • 2021-03-05
    • 1970-01-01
    • 2016-08-17
    相关资源
    最近更新 更多