【问题标题】:What exactly happens when you assign self to delegate?当您将 self 分配给委托时,究竟会发生什么?
【发布时间】:2020-06-22 01:18:13
【问题描述】:

我是 Swift 新手,我很难理解将 self 分配给代表的目的。部分困难源于委托似乎以两种不同的方式使用。

首先是在特定事件发生时将消息从一个类发送到另一个类的方法,类似于状态管理。其次是使“一个类或结构能够将其某些职责移交(或委托)给另一种类型的实例”,如documentation 中所述。我有一种感觉,这两者本质上是相同的,我只是不明白。

protocol PersonProtocol {
    func getName() -> String
    func getAge() -> Int
}

class Person {
    var delegate: PersonProtocol?
    
    func printName() {
        if let del = delegate {
            print(del.getName())
        } else {
            print("The delegate property is not set")
        }
    }
    
    func printAge() {
        if let del = delegate {
            print(del.getAge())
        } else {
            print("The delegate property is not set")
        }
    }
}

class ViewController: UIViewController, PersonProtocol {
    var person: Person!
    
    override func viewDidLoad() {
        person.delegate = self
        
        person.printAge()
        person.printName()
    }
    
    func getAge() -> Int {
        print("view controller")
       return 99
    }
    
    func getName() -> String {
        return "Some name"
    }
}

在这种情况下person.delegate = self 的目的是什么?没有它,ViewController 不是已经需要符合 PersonProtocol 了吗?

【问题讨论】:

    标签: ios swift delegates swift-protocols


    【解决方案1】:

    感觉这两者本质上是一样的

    第一个是第二个的特例。 “将消息从一个类发送到另一个类”只是“移交某些职责”的一种特定方式。 “信息”就是“责任”

    在这种情况下person.delegate = self 的目的是什么?

    在这里,person 将它的一些职责委托(即放弃)另一个对象。它通过向另一个对象发送消息来做到这一点。首先,它需要确定可以将这些职责委托给哪些对象。这是通过要求其delegate 符合PersonProtocol 来实现的,因为PersonProtocol 定义了Person 将要发送的消息。

    接下来,person 需要确切地知道它应该将这些消息发送到哪个对象。这就是person.delegate = self 所做的。请记住,person 在此之前对您的ViewController 一无所知。而不是= self,你可以说:

    person.delegate = SomeOtherClassThatConformsToPersonProtocol()
    

    person 会将其消息发送到该对象,而您的ViewController 中的方法将不会被调用。

    如果没有它,ViewController 不是已经需要符合 PersonProtocol 了吗?

    正确,但没有它,person 不知道应该将消息发送到哪个对象,因此,ViewController 中的方法将不会被调用。


    请注意,delegate 属性应声明为weak 以避免保留循环。当您执行person.delegate = self 时,您会得到一个保留周期:self 具有对person 的强引用,person 也通过delegate 属性对self 具有强引用。

    【讨论】:

    • 感谢您的回答。所以ViewControllerPerson 类的代表,它能够从Person 调用方法?这给Person 带来了什么价值?还是发给ViewController
    • @Kevvv ViewControllerperson 的代表,正确。 Person 现在可以在需要姓名或年龄时通知 ViewController。正如您可能已经意识到的那样,Person 不应该这样工作...Person 应该知道他们自己的年龄和姓名,而不是询问ViewController...所以你给你的班级起的名字和协议是如何使用委托模式的一个非常糟糕的例子。可以在您问题中链接的文档中找到更好的示例。在那里,SnakesAndLadders 通知其代表游戏何时开始和结束等。
    • UIKit 的一个例子是UITableViewDelegate 通过tableView(_:heightForRowAt:) 询问其代表每行的高度应该是多少。
    【解决方案2】:

    如果你注意到你的 Person 类里面,delegate 是 nil。如果不执行 person.delegate = self,delegate 将保持为 nil。

    换句话说,将 ViewController 分配给 person.delegate 可以让 Person 识别委托人是谁(即拥有对 ViewController 的引用),这样您就可以成功地执行像 delegate?.getName() 或 delegate? 这样的语句。来自 Person 类的 getAge()。

    【讨论】:

      【解决方案3】:

      这意味着Person 不能getName()getAge() 所以Person 类将其委托给其他数据源。 假设您的视图控制器有一个数据源类 PersonDataSource 处理 API 以获取此信息所以

      class PersonDataSource: PersonProtocol { 
          func getAge() -> Int {
              print("view controller")
             return 99
          }
          
          func getName() -> String {
              return "Some name"
          }
       } 
      

      所以视图控制器看起来像这样

      class ViewController: UIViewController {
          var person: Person!
          var personDataSource = PersonDataSource()
          override func viewDidLoad() {
              person.delegate = personDataSource
              
              person.printAge()
              person.printName()
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-29
        • 2023-04-01
        • 2022-11-27
        • 2018-12-01
        • 2015-12-25
        • 1970-01-01
        • 2014-08-12
        • 2015-10-23
        相关资源
        最近更新 更多