【问题标题】:When to init a delegate in Swift何时在 Swift 中初始化委托
【发布时间】:2015-09-14 21:14:57
【问题描述】:

我有一个基本问题。我正在从事一个具有许多委托模式的项目,并希望参考初始化它们的最佳方式..

以下是我对测试委托提出的一些想法:

选项 1:

失败是因为我在 super.init() 之前将委托初始化为 self

protocol MyClassDelegate {
    func doSomething()
}

class MyClass {

    var delegate: MyClassDelegate!

    init(delegate: MyClassDelegate){
        self.delegate = delegate
    }

    func myClassFuction(){
        self.delegate.doSomething()
    }
}


class ClassConformingToDelegate: NSObject, MyClassDelegate {

    let myClass: MyClass

    override init(){
        myClass = MyClass(delegate: self) // Error because it's called before super.init
        super.init()
    }        

    func doSomething(){
        //called from the delegate
    }
}

选项 2:

它可以工作,但是我冒着让委托为零的风险。每次我想调用一个方法时,我是否必须运行一个“如果委托!=零”检查?有办法解决吗?以这种方式初始化委托是一种好习惯吗?

protocol MyClassDelegate {
    func doSomething()
}

class MyClass {

    var delegate: MyClassDelegate!

    init(){
    }

    func myClassFuction(){
        self.delegate.doSomething() // might fail if delegate is nil
    }
}


class ClassConformingToDelegate: NSObject, MyClassDelegate {

    let myClass: MyClass

    override init(){
        myClass = MyClass()
        super.init()
        myClass.delegate = self // works because called after super.init
    }        

    func doSomething(){
        //called from the delegate
    }
}

这些只是一些想法。我只是想学习最好的方法。我愿意接受所有建议。

谢谢!!

【问题讨论】:

  • 委托通常应该被声明为weak,否则你可能会遇到引用周期问题。见:en.wikipedia.org/wiki/…
  • @WolfgangSchreurs 在 Swift 中,协议也可以由结构体实现,并且结构体不能有保留循环; Swift 中的枚举也是如此。为了使变量 week 具有协议类型是不够的,协议需要一个对象约束。请参阅下面的答案。

标签: xcode cocoa delegates swift2


【解决方案1】:

选项 2 看起来更好。但是,在这种情况下,建议使用可选项作为您的委托类型。这样,您无需在每次要使用它执行任务时检查“if delegate != nil”。您可以简单地使用可选链接,该链接专为您希望仅在可选包含值时才对其执行任务的情况而设计。

protocol MyClassDelegate {
    func doSomething()
}

class MyClass {

    var delegate: MyClassDelegate?

    init(){
    }

    func myClassFuction(){
        self.delegate?.doSomething() // will do nothing if delegate is nil
    }
}


class ClassConformingToDelegate: NSObject, MyClassDelegate {

    let myClass: MyClass

    override init(){
        myClass = MyClass()
        super.init()
        myClass.delegate = self
    }        

    func doSomething(){
        //called from the delegate
    }
}

【讨论】:

  • 为什么选项 2 更好? @vinn
  • 可能是因为它允许你不要设置一个,或者稍后再设置
  • 但是如果到目前为止,在您的代码中每次使用“MyClass”时都立即设置它的委托,那么您可以将它包含在“MyClass”初始化程序中,这样您就永远不会忘记设置它并且得到意想不到的行为。如果你后来决定要在没有委托的情况下使用“MyClass”,那么在那一点上继续并将它从初始化程序中删除,但至少这会让你考虑你在做什么并思考你为什么会这样做那样。一开始是限制性的,只有在必须且有充分理由时才允许限制较少的行为。
【解决方案2】:

使用延迟初始化来解决该问题。

protocol MyClassDelegate: class {

    func doSomething()

}


class MyClass {

    private(set) weak var delegate: MyClassDelegate?

    func myClassFuction ( ) {
        self.delegate?.doSomething()
    }

    init ( delegate: MyClassDelegate ) {
        self.delegate = delegate
    }

}


class ClassConformingToDelegate: NSObject, MyClassDelegate {

    lazy private(set) var myClass: MyClass = {
            return MyClass(delegate: self)
        }()

    func doSomething ( ) {
        //called from the delegate
    }
}

没有公共设置器的变量myClass 将在ClassConformingToDelegate 本身或某些外部代码第一次访问它时被初始化。如果您想确保在创建新的ClassConformingToDelegate 对象时始终对其进行初始化(因为它的唯一创建可能会产生副作用,例如注册通知等),只需从init 访问它即可:

override
init ( ) {
    super.init()
    _ = self.myClass
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 2022-08-18
    • 1970-01-01
    • 2012-08-26
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    相关资源
    最近更新 更多