顯示具有 iOS 標籤的文章。 顯示所有文章
顯示具有 iOS 標籤的文章。 顯示所有文章

2018年7月8日 星期日

Xcode Storyboard and NSCoder (Codable in swift)


.plist file 是一個 xml 格式的文件,意思是 Property List

Swift 可以用 Codable protocol 來處理這類文件

而 Xcode 的 Storyboard 也是類似的方式處理 View,只是用的是 OC 的 NSCoder

每當我們在 Storyboard 上更改什麼東西時,就會透過 NSCoder 轉換(encoding)成 Property 存在某個 .plist 文件裡,而當 App 啟動時則再用 NSCoder 讀取這些 Property 再轉化(decoding)為 UI 元件。

其實角色就像是 serializer

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.

2018年6月28日 星期四

iOS learning

Table View 兩種:
* plain - 一般的
* grouped - 灰底,像設定檔

TableView 有 cell 和 row 的概念

可以想像 cell 就是顯示出來的 row,是會被 reuse 的 object
而 row 就是 table view 有的全部資料

所以 cell 要有 identifier,這樣才可以被 reuse,代表是哪一種 cell

TableView 要有 data 就要 implement data source protocol, 所謂 protocol 就是規定好的 functions 要你 implement

此時 ViewController 就是 table view data source 的 delegate,因為 data 是什麼都跑來問 view controller 了




story board 為元件加上 tag,就可以用 cell.viewWithTag(tag) 來拿到

cell 裡的 label 要用這樣的拿法因為如果用 @IBOutlet 就只能 reference 一個,是不合理的


UITableViewDataSource => 顯示的資料
UITableViewDelegate => 處理行為

```swift
if let cell = tableView.cellForRow(at: indexPath) {
    if cell.accessoryType == .none {
      cell.accessoryType = .checkmark
    } else {
      cell.accessoryType = .none
    }
  }
```

用 if let 的方法可以處理 let 後面的 expression 是 nil 的情況,是常用的技巧


```swift
override func tableView(_ tableView: UITableView,
      numberOfRowsInSection section: Int) -> Int {}
```

這裡的 numberOfRowsInSection 是外部參數,section 是區域參數,function 裡面用 section,外面的 function 是看到 numberOfRowsInSection,至於 _ 底線就是不想要有外部名稱時用的


```swift
// This declares that items will hold an array of ChecklistItem
// objects but it does not actually create that array.
// At this point, items does not have a value yet.
var items: [ChecklistItem]

required init?(coder aDecoder: NSCoder) {
// This instantiates the array. Now items contains a valid array
// object, but the array has no objects inside it yet.
items = [ChecklistItem]()
}
```