Chapter 4: Delegation Pattern

大綱

When should you use it?

  • The delegation pattern enables an object to use another “helper” object to provide data or perform a task rather than do the task itself.

    • An object needing a delegate, also known as the delegating object. It’s the object that has a delegate.

      • The delegate is usually held as a weak property to avoid a retain cycle where the delegating object retains the delegate, which retains the delegating object.

  • A delegate protocol, which defines the methods a delegate may or should implement.

  • A delegate, which is the helper object that implements the delegate protocol.

  • When should you use it?

    • Use this pattern to break up large classes or create generic, reusable components.

      • Apple frameworks commonly use the term DataSource to group delegate methods that provide data. For example, UITableViewDataSource is expected to provide UITableViewCells to display.

      • Apple frameworks typically use protocols named Delegate to group methods that receive data or events. For example, UITableViewDelegate is notified whenever a row is selected

Playground example

// 1. A delegate protocol
public protocol MenuViewControllerDelegate: class {
  func menuViewController(
    _ menuViewController: MenuViewController,
    didSelectItemAtIndex index: Int)
}

// 2. An object needing a delegate
public class MenuViewController: UIViewController {

  // 3. A delegate
  public weak var delegate: MenuViewControllerDelegate?

  @IBOutlet public var tableView: UITableView! {
    didSet {
      tableView.dataSource = self
      tableView.delegate = self
    }
  }

  private let items = ["Item 1", "Item 2", "Item 3"]
}

// MARK: - UITableViewDataSource
extension MenuViewController: UITableViewDataSource {

  public func tableView(_ tableView: UITableView,
                 cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",
                                             for: indexPath)
    cell.textLabel?.text = items[indexPath.row]
    return cell
  }

  public func tableView(_ tableView: UITableView,
                 numberOfRowsInSection section: Int) -> Int {
    return items.count
  }
}

// MARK: - UITableViewDelegate
extension MenuViewController: UITableViewDelegate {

  public func tableView(_ tableView: UITableView,
                 didSelectRowAt indexPath: IndexPath) {
    // 4. 將events發送出去
    delegate?.menuViewController(self,
                                 didSelectItemAtIndex:  indexPath.row)
  }
}

What should you be careful about?

  • Be careful about creating too many delegates for an object.

    • If an object needs several delegates, this may be an indicator that it’s doing too much. Consider breaking up the object’s functionality for specific use cases, instead of one catch-all class.

  • You should also be careful about creating retain cycles. Most often, delegate properties should be weak.

Tutorial project

Key points

  • The delegation pattern has three parts: an object needing a delegate, a delegate protocol and a delegate.

  • This pattern allows you to break up large classes and create generic, reusable components.

  • Delegates should be weak properties in the vast majority of use cases.

Last updated

Was this helpful?