今更だけど独自クラスでQuick Lookを使う方法について調べた

[WWDC 2014: Debugging in Xcode 6](https://developer.apple.com/videos/play/wwdc2014/413/)で発表されたカスタムQuick Lookが面白そうなので今更ですが触ってみました。

# Quick Lookとは

オブジェクト変数の現在の状態を、ポップアップ表示でグラフィカルに表示してくれる機能です。クイックルックボタンをクリックするか、Xcode下部のデバッグアリアで変数を選択した状態でスペースキーを押せば見ることができます。

![スクリーンショット 2017-01-20 19.20.52.png](https://qiita-image-store.s3.amazonaws.com/0/100736/01dc16c2-8dd1-a5c8-4484-dbd392c45f8d.png)

クイックルックで見ることができるオブジェクトタイプは次の通りです（[Quick Look Data Types](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/debugging_with_xcode/chapters/quick_look_data_types.html)から抜粋）。

![スクリーンショット 2017-01-20 19.42.35.png](https://qiita-image-store.s3.amazonaws.com/0/100736/475934f6-78b5-ad9a-bdd4-e7799d8a627d.png)

上記に当てはまらないタイプだったとしてもデフォルトのクイックルックは表示されます。
![スクリーンショット 2017-01-20 19.23.58.png](https://qiita-image-store.s3.amazonaws.com/0/100736/e17bb9df-7dbf-17ec-f72f-4d01959ae61a.png)

自分が作ったオブジェクトクラスでもレンダリングメソッドを追加することでクイックルックを拡張させて使うことができます。今回はその方法を書きます。

# 独自クラスでQuick Lookを使う

## debugQuickLookObjectメソッド

クイックルックを使うには独自クラス内で`debugQuickLookObject`という名のメソッドを実装します。この関数はブレークポイントで止めてクイックルックボタンをタップされた時に呼ばれます。

```swift
func debugQuickLookObject() -> AnyObject? {
  // 色々やる
  return [オブジェクト]
}
```

戻り値には表現したいデータのオブジェクトを渡すのですが、何でも返せばいいというわけではありません。以下のうちのどれかにする必要があります。
![スクリーンショット 2017-01-20 23.05.19.png](https://qiita-image-store.s3.amazonaws.com/0/100736/5d665d02-8499-2318-7f3b-41eb7600cb42.png)
※[Get QuickLook Preview of Swift objects in XCode](http://azimi.me/2015/01/03/quick-look-preview-ios-swift.html)から抜粋

## 注意点

このメソッドは一時停止しているアプリのデバッグ時に走るメソッドであるため、実装の無駄をなくして必要なコードだけを書くべきだということです。実行中のアプリに影響が出る可能性を考慮し、もし可能であれば戻り値をキャッシュすることも考えます。

## 実装

では実際に試してみます。試しにこんなviewを作って
![スクリーンショット 2017-01-21 14.18.59.png](https://qiita-image-store.s3.amazonaws.com/0/100736/2e067973-5134-af3f-4677-906cc5f021c1.png)
こんな実装をしておきます。

```swift
class CustomView : UIView {
    
    @IBOutlet var customView: UIView!
    @IBOutlet weak var viewTitle: UILabel!
    @IBOutlet weak var photoTitle: UILabel!
    @IBOutlet weak var imageView: UIImageView!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.comminInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.comminInit()
    }
    
    private func comminInit() {
        let view = Bundle(for: type(of: self)).loadNibNamed("CustomView", owner: self, options: nil)?.first as! UIView
        self.addSubview(view)
        customView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
    }
    
    func debugQuickLookObject() -> AnyObject? {        
        return "viewTitle = \(viewTitle.text), photoTitle = \(photoTitle.text)" as AnyObject?
    }    
}
```

この状態で呼び出し側でブレークポイントをかけてクイックルックを見るとこうなります。
![スクリーンショット 2017-01-21 14.24.01.png](https://qiita-image-store.s3.amazonaws.com/0/100736/ff2920d8-92ca-03bb-b972-7241d120d5a2.png)
ちゃんとStringで取れてます。
もちろん次のようなコードにすれば

```swift
func debugQuickLookObject() -> AnyObject? {        
    return imageView
}
```

画像を確認することができます。
![スクリーンショット 2017-01-21 14.31.27.png](https://qiita-image-store.s3.amazonaws.com/0/100736/1d0d0ae7-f688-ae9a-d522-d962930f3230.png)

ちなみに無理やりですがこのようなコードを書くと

```swift
func debugQuickLookObject() -> AnyObject? {
    let urlStr:String = "https://www.google.co.jp/"
    let url:NSURL = NSURL(string:urlStr)!
    return url as AnyObject?
}
```

webページが表示されます。文字も入力できます。
![スクリーンショット 2017-01-21 14.40.32.png](https://qiita-image-store.s3.amazonaws.com/0/100736/0b6ea114-397b-7f43-9cb8-590fa2a36b59.png)
ちなみにEnter押して検索実行したらこんな表示が出てきました。
![スクリーンショット 2017-01-21 14.41.50.png](https://qiita-image-store.s3.amazonaws.com/0/100736/afe41a66-7325-ba80-019d-4cd75077dceb.png)
openにするとSafariでgoogleが表示されました。

# 思ったこと

以前Javaを書いていた時にtoStringをオーバーライドして各プロパティの値を出力していたときがあり、それと同じようなものかなと思いました。
わざわざこれを仕込んでおく必要がある場面がどれくらいあるかわかりませんが、グラフィカルに状態を表示してくれるのは良いことですし見たい値を一気に見られるように設定しておけば楽になることもあるので覚えておいても損はない機能かなと思いました。