2018年6月30日 星期六

iOS 在 screens 之間傳資料


所謂 screens  之間就是 ViewControllers 之間,這裡討論的是 A screen 叫出了 B screen,但 B screen 想要送資料回 A screen 時該怎麼做。

通常如果是 A controller contains B controller (A screen 叫出了 B screen),那麼不應該讓 B screen 知道關於 A controller 的細節,否則就是 circular dependency,意思就是不該這樣做:


```swift
class BViewController: UITableViewController, . . . {

  // This variable refers to the other view controller
  var aController: AViewController

  @IBAction func done() {
    // Create the new checklist item object
    let item = ChecklistItem()
    item.text = textField.text!

    // Directly call a method from AViewController
    aController.add(item)
  }
}
```

有時候有些 screen 是要被很多 ViewController 呼叫的,所以如果這樣做也同時失去了可以被很多 controller 呼叫的彈性

比較好的作法應該是用 delegate



如此一來 B 就不知道 A 是誰,B 只知道有哪些 delegate 可以用。
那怎麼 delegate 呢?在 Swift 裡面就是寫一個 protocol,Protocol 的功用就是給有 implement 這個 protocol 的 class 一些規範,說白了就是定義有哪些 functions, 哪些是 required 哪些是 optional

example:

```swift
protocol AddItemViewControllerDelegate: class {
  func addItemViewControllerDidCancel(
                          _ controller: AddItemViewController)
  func addItemViewController(
                 _ controller: AddItemViewController,
         didFinishAdding item: ChecklistItem)
}
```

從此之後 B controller 只需要

```swift
weak var delegate: AddItemViewControllerDelegate?
```

就可以操作 delegate 的 controller 了

通常 delegate 會是 weak variable 以及 optional


optional 的原因是 delegate 本來就 optional,要不要 implement 都沒關係。另外一個主要原因是當 StoryBoard load 這個 controller 時,並不知道 delegate 是誰,所以應該要是 optional。


通常會在 prepare 的 function 指派 delegate,此例就是在 A segue 到 B 時指派 A 成為 B 的 AddItemViewControllerDelegate 的 delegate,在 A controller 裡面加上:

```swift
override func prepare(for segue: UIStoryboardSegue,
                         sender: Any?) {
  // 1
  if segue.identifier == "B" {
    // 2
    let controller = segue.destination
                     as! BController
    // 3
    controller.delegate = self
  }
}
```


Delegates in five easy steps:


These are the steps for setting up the delegate pattern between two objects, where object A is the delegate for object B, and object B will send messages back to A. The steps are:
1 - Define a delegate protocol for object B.
2 - Give object B a delegate optional variable. This variable should be weak.
3 - Update object B to send messages to its delegate when something interesting happens, such as the user pressing the Cancel or Done buttons, or when it needs a piece of information. You write delegate?.methodName(self, . . .)
4 - Make object A conform to the delegate protocol. It should put the name of the protocol in its class line and implement the methods from the protocol.
5 - Tell object B that object A is now its delegate.

沒有留言:

張貼留言