xibファイルを読み込んでNSTableViewを作成する

# 概要
- 以下のような簡単なテーブルを作っていきます。
- （基本的な所は省略して、忘備録的に書いていますので細かい所はサンプル参照ということでご容赦を…。）

![-w450](https://i.imgur.com/QfYZlnL.jpg)

- また以下のテーブルのセルは`xib`ファイルから読み込んだものを使用しています。

![-w450](https://i.imgur.com/MUABqsd.jpg)

# GitHub
- https://github.com/pommdau/Qiita_NSTableViewDemo

# 参考
- [Macアプリ初心者：NSTableView でカスタムした一覧を作ってみる \- Qiita](https://qiita.com/ynozue/items/da96d8bf1a2e2e1f3da0)
    - 別Xibにしない場合について書かれています。

# テキストだけの単純なテーブル
## Storyboard側

- `TableView`の`delegate`と`datasource`をコントローラにバインディング

![-w1682](https://i.imgur.com/nHWfxim.jpg)

- `CellView`の`Identifier`を`MyView`に設定しておく

![-w1703](https://i.imgur.com/IwFUvME.jpg)

## コード

- 表示するデータを用意

```swift
var messages = ["sample message 1",
                "sample message 2",
                "sample message 3"]
```

- テーブル表示に必要なメソッド2種を実装する
- `NSUserInterfaceItemIdentifier(rawValue: "MyView")`により、<br>Storyboardで指定した`MyView`を読み込んでコード内で使用することができる

```swift
extension StandardTableViewController : NSTableViewDelegate, NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        return messages.count
    }
    
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        guard let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "MyView"), owner: self) as? NSTableCellView else {
            return NSTableCellView()
        }
        
        cellView.textField?.stringValue = messages[row]
        
        return cellView
    }
}
```

# カスタムXibを用いたテーブルビュー
## 概要
- 別のXibファイルをセルに使用したい場合の実装です。

## 実装
### カスタムセルのクラス（CustomTableCellView.swift）

- カスタムセルのため、`NSTableCellView`のサブクラスを作成します。
- テーブルの`delegate`設定等は前述と同じなので割愛しています。

```swift
protocol CustomTableCellViewDelegate: class {
    func selectionButtonClicked(for cell: NSTableCellView)
}

class CustomTableCellView: NSTableCellView {

    @IBOutlet weak var cellImageView: NSImageView!
    @IBOutlet weak var titleLabel: NSTextField!
    @IBOutlet weak var descriptionLabel: NSTextField!
    @IBOutlet weak var selectionButton: NSButton!
    
    var delegate: CustomTableCellViewDelegate?
    
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

    }
    
    func configure(for cellData: CustomCellData) {
        self.cellImageView.image          = cellData.image
        self.titleLabel.stringValue       = cellData.title
        self.descriptionLabel.stringValue = cellData.descriptionText
    }
    
    
    // MARK: - Actions
    
    @IBAction func selectionButtonClicked(_ sender: NSButton) {
        // セルのボタンのアクションをコントローラに返すため、delegateを使用する
        delegate?.selectionButtonClicked(for: self)
    }
    
}
```

### カスタムセルのxib（CustomTableCellView.xib） 

- カスタムセルのUI側です。
- クラスを作成する`CustomTableCellView`に指定します
- セルの`identifier`等の設定は不要です。
    - `CustomTableViewController`の`tableView.register`で設定するからですね

![-w1412](https://i.imgur.com/pbi69ZT.jpg)


### 定数定義ファイル（Konst.swift）
- identifier等に使用する定数をファイルで定義しておきます

```swift
struct Konst {

    struct SegueIdentifier {
        static let showStandardTableViewController = "ShowStandardTableViewController"
        static let showCustomTableViewController   = "ShowCustomTableViewController"
    }

    struct CellIdentifier {
        static let customTableCellView = "CustomTableCellView"
    }

    struct NibName {
        static let customTableCellView = "CustomTableCellView"
    }
}
```

### ビューコントローラ（CustomTableViewController.swift）
- 別のxibファイルから読み込むため、`viewDidLoad`で`tableView`に`xib`の登録を行う
    - iOSでカスタムセルを使う際と同じですね。

```swift
// 別のXibファイルから読み込む場合は登録が必要
tableView.register(NSNib(nibNamed: Konst.NibName.customTableCellView, bundle: nil),
                    forIdentifier: NSUserInterfaceItemIdentifier(rawValue: Konst.CellIdentifier.customTableCellView))
tableView.reloadData()
```

- 同様にテーブル表示に必要なプロトコルメソッドを実装
- `cell`のUI設定はcell側 = Model側に任せてしまう。教本でよく見る実装です。
    - `cellView.configure(for: cellDataList[row])`



```swift
// MARK: - NSTableViewDelegate, NSTableViewDataSource Methods

extension CustomTableViewController: NSTableViewDelegate, NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        return cellDataList.count
    }
    
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        guard let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: Konst.CellIdentifier.customTableCellView), owner: self)
            as? CustomTableCellView else {
            return NSTableCellView()
        }
        
        cellView.delegate = self
        cellView.configure(for: cellDataList[row])
        
        return cellView
    }
}
```

- カスタムセル内のボタンのアクションを受け取るため、delegateパターンを使用しています。

```swift
// CustomTableCellViewDelegate Methods

extension CustomTableViewController: CustomTableCellViewDelegate {
    func selectionButtonClicked(for cell: NSTableCellView) {
        let rowIndex = tableView.row(for: cell)  // 選択されたcellViewのIndexを取得できる
        print("selected row: [\(rowIndex)]")
    }
}
```