OS X アプリケーション(Today Extension)開発に触れてみる 🕺

この記事はRetty Inc. Advent Calendar 2017 15日目の記事です。
昨日は @r4-keisuke さんによる [ElasticsearchでRettyのサジェスト検索を作ったときの苦労話](https://qiita.com/r4-keisuke/items/391da271591ee6d62fde) でした。

こんにちは  :innocent:  Rettyでエンジニアをしている @isaoeka です。
最近は `アイカツ！` にハマっています、切実にアイカツ友達が欲しいです。

というのはいいとして、掲題にもありますが今回はOS Xアプリケーションの Today Extensionに触れてみた話をしていきます。

また、今回この記事を書くにあたって作った[サンプル](https://github.com/isaoeka/WidgetSample-OSX)をGithubに上げましたので、よければ動かしてみてください。

## TL; DR

- Cocoa App  の Today Extension を作って遊んでみました
- UITableView likeなNSTableViewを作る
- とりあえず動かしたい場合は [こちら](https://github.com/isaoeka/WidgetSample-OSX)

## Qiitaの記事をTableViewに表示するウィジェットを作ってみる

作りながら学んでいきたいため、作るものを定義します。

簡単なモノにしたいので、TableViewにQiitaの記事を表示し選択することでブラウザを開く... といったウィジェットを作っていくことにしましょう。

### プロジェクトの作成 

| プロジェクトの作成 | ターゲットの追加 |
|---|---|
| ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20511/5a9ef41a-357c-5c4d-7f7f-2d7fa0c3b4c1.png) | ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20511/19569ea0-d755-c08a-4c39-d09fc1ade63b.png) |

細かい説明は省きますが、`Cocoa App` を作成し、ターゲット(Today Extension)を追加します。

プロジェクト作成直後はLabelが乗っている状態です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/20511/deb7f7ea-6600-ffb9-bb56-a145a991b9aa.png)

### NSTableViewの追加 ( NSTableViewをUITableView Likeにする )

NSTableViewはデフォルトのまま使うと下記のように、Columnが2つのFinderのような見た目をしています。

| デフォルト | よく見るWidget例 |
|---|---|
| ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20511/d3f3547d-f523-132c-445a-acd14ed5841e.png) | ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20511/a30eae91-14d0-45e8-f156-581106df1f37.png) |

今回は天気ウィジェットのようなセルにしたい為、NSTableView・表示するセルをUITableView likeに寄せてい行きます。

下記のような設定で近づきます。
- Table ViewのColumn数を1つに
- Scroll ViewのDrawBackGroundをoff
- tableView.headerViewを非表示
- Separaterの描画
- NSTableCellViewを拡張する

```swift

// 親ViewのScrollViewの背景を描画させない
scrollView.drawsBackground = false

// Headerの非表示, 背景色の透過
tableView.headerView = nil
tableView.backgroundColor = .clear

// Separaterの描画
tableView.gridColor = .lightGray
tableView.gridStyleMask = .solidHorizontalGridLineMask
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20511/6c119944-c9fc-8485-40f3-47fb54ae5a72.png)

まぁ及第点、オケオケオッケー。
このあたりで、もうCococaが別のViewComponentを用意してくれても良いのでは...？と思うなどしていました。

一応 `NSTableViewDataSource` の記述も記載しておきます。
この当たりのInterfaceはUITableViewと近く, iOSエンジニアであれば困ること無く扱えるかと思います。

```swift
// private let dataList: [String] = ["hoge', "fuga", "piyo"]

extension TodayViewController: NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        return self.dateList.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        guard let view = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "cell"), owner: self),
            let cell = view as? NSTableCellView
            else {
            return nil
        }
        let title = self.dateList[row]
        cell.textField?.stringValue = title
        return cell
    }
}
```

### OS X app からHttp Requestをする場合の注意点　

Xcode9.xで作成したプロジェクトはデフォルトではHttp Requestが下記エラーが出てRequestに失敗します。

```sh

Task <4140282C-D10A-4FCE-A928-F432266702F4>.<1> HTTP load failed (error code: -1003 [10:-72000])
2017-12-14 04:44:17.823992+0900 TodayExtension[53431:2423476] Task <4140282C-D10A-4FCE-A928-F432266702F4>.<1> finished with error - code: -1003
Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x604000057250 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=-72000, _kCFStreamErrorDomainKey=10}}, NSErrorFailingURLStringKey=https://qiita.com/api/v2/users?page=1&pre_page=20, NSErrorFailingURLKey=https://qiita.com/api/v2/users?page=1&pre_page=20, _kCFStreamErrorDomainKey=10, _kCFStreamErrorCodeKey=-72000, NSLocalizedDescription=A server with the specified hostname could not be found.}
```

結論から言うと [こちら](https://qiita.com/codelynx/items/35eba001de1ecee6826e) の情報で解消しました。
全く同じ発想で 「これはATSだな」と思うも違い、路頭に迷っていたところを助けられました。

## まとめ

個人的にiOS・OS Xのウィジェットを使う機会が多く「もっと対応アプリ増えてくれ！」という動機からつらつらと書いてみたのですが、いかがだったでしょうか？

感想としては、 `Cocoa` の操作感が `UIKit` と近いようで遠い為、普段iOSアプリを作っている人でも慣れるまで大変だろうなぁというところでしょうか。
また、iOSと比べるとOS X アプリケーション開発の情報は非常に少なく、Document, [Guides and Sample Code](https://developer.apple.com/library/content/navigation/#section=Platforms&topic=macOS), OSSやstackoverflowを徘徊することになります...。

この記事内ではExportするところまで行けませんでしたが、個人配布するところにも興味があるので追って記事を書ければなと思っています。

明日は スズタク ( @takumi-suzuki ) の [RDS からEC2へ Multi-master replicationを組んでみた](https://qiita.com/takumi-suzuki/items/3bcedbd431c89e9d4ee9) です。お楽しみに〜