SwiftでTableViewCellの高さを動的に変える

#はじめに
題名の通り、TableViewCellの高さを動的に変えてみます。
Self-Sizing Cellsとかいうやつです。


本記事のサンプルは、Xcode Ver7.3.1で実装しました。
iOS 8.0以降対象です。

#Self-Sizing Cells??
セルの高さを自力で計算することなく動的な高さを持つセルを定義できるものです。

#完成イメージ

name, commentを持つJSONからデータを取得します。
サンプルなので、表示する文字列はテキトーです。

```json:profileSample.json
{
    "profile": [
                {"name": "AAA", "comment": "abcd123"},
                {"name": "BBB", "comment": "あいう\nえお"},
                {"name": "CCC", "comment": "こめんと\nコメント\nComment"},
                {"name": "DDD", "comment": "01234\n56789\n98765\n43210"},
                {"name": "EEE", "comment": "コメント\nコメント\nコメントコメント\nコメコメントントコメントコメント\nabc123"},
                {"name": "FFF", "comment": ""},
                {"name": "GGG", "comment": "abcd123"},
                {"name": "HHH", "comment": "あいう\nえお"},
                {"name": "III", "comment": "こめんと\nコメント\nComment"},
                {"name": "JJJ", "comment": "01234\n56789\n98765\n43210"},
                {"name": "KKK", "comment": "コメント\nコメント\nコメントコメント\nコメコメントントコメントコメント\nabc123"},
                {"name": "LLL", "comment": ""},
                {"name": "MMM", "comment": "コメント\nコメント\nコメント\nコメント\nコメント\nコメント"},
                {"name": "NNN", "comment": "apple\niOS"},
                {"name": "OOO", "comment": ""},
                {"name": "PPP", "comment": "0\n11\n222\n3333\n44444\n555555\n6666666\n77777777\n888888888\n9999999999"},
                ]
}

```


このデータから、
名前（赤字）とコメント（黒字、複数行）を持つTableViewCellを作ります。
<img width="414" alt="Simulator Screen Shot 2016.09.13 1.44.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/103695/6aac783f-58be-9692-1259-a17ea168ae0f.png">

#Cell内に配置したパーツに適切な制約をつける
本サンプルでは、Cell内にnameLabelとcommentLabelの二つ配置しています。
それぞれのラベルに適切な制約をつけてあげます。

nameLabelは、
上左右 Constrain 0
下 Constrain 8としました。

commentLabelは、
下左右 Constrain 0
上 Constrain 8としました。

（単に上下左右に制約をつけただけです。）

<img width="1023" alt="スクリーンショット 2016-09-13 1.58.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/103695/ccfbe497-43f8-8d8b-6690-c3d9c0a63315.png">


また、commentLabelは複数行のテキストを表示するので
Linesに0を設定しておきます。
<img width="1019" alt="スクリーンショット 2016-09-17 21.03.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/103695/501ee010-5195-a130-4352-b27a1bfdaaf7.png">



#TableViewの設定
**estimatedRowHeightを設定する**

`tableView.estimatedRowHeight = 66`
セルの高さを計算する直前までの高さになります。
（デフォルトの高さというイメージですかね。）


**rowHeightにUITableViewAutomaticDimensionを設定する**
`tableView.rowHeight = UITableViewAutomaticDimension`


estimatedRowHeightに任意の値を設定し、
rowHeightにUITableViewAutomaticDimensionを設定することで
動的にセルの高さを設定してくれるようになります。

その他の部分は、基本的なTableViewの実装と変わりません。
セルに表示するデータを取得したり、UITableViewDataSourceのデリゲートメソッドを定義したりするだけです。(基本的なTableViewの実装部分については説明を割愛させていただきます。)

#作成したコード

```swift:ProfileViewController.swift
import UIKit

struct ProfileModel {
    var name = ""
    var comment = ""
}

struct ProfilesModel {
    var profiles = [ProfileModel]()
}

class ProfileViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    var profilesModel = ProfilesModel()
    

// MARK: Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.estimatedRowHeight = 66
        tableView.rowHeight = UITableViewAutomaticDimension
        
        guard let jsonFilePath = NSBundle.mainBundle().pathForResource("profileSample", ofType: "json") else {
            return
        }
        // JSONファイルのデータ整形し、profilesModelにセットする
        JsonParser.parse(&profilesModel, jsonFilePath: jsonFilePath)
        
        
        tableView.dataSource = self
    }
}


// MARK: UITableViewDataSource
extension ProfileViewController: UITableViewDataSource {
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return profilesModel.profiles.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! ProfileCell
        cell.nameLabel.text = profilesModel.profiles[indexPath.row].name
        cell.commentLabel.text = profilesModel.profiles[indexPath.row].comment
        return cell
    }
}
```


```swift:ProfileCell.swift
import UIKit

class ProfileCell: UITableViewCell {
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var commentLabel: UILabel!
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        nameLabel.textColor = UIColor.redColor()
    }
}
```

JSONのparseしているのは、こちら。

```swift:JsonParser.swift
import UIKit

class JsonParser: NSObject {
    /// JSONをparseする
    class func parse(inout profilesModel: ProfilesModel, jsonFilePath: String) {
        guard let data = NSData(contentsOfFile: jsonFilePath) else {
            return
        }
        
        let dictionary:NSDictionary = try!
            NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
        
        var profileModel = ProfileModel()
        
        let profiles = dictionary["profile"] as! Array<NSDictionary>
        for profile in profiles {
            profileModel.name = profile["name"] as! String
            profileModel.comment = profile["comment"] as! String
            
            profilesModel.profiles.append(profileModel)
        }
        
    }
}
```

#さいごに
TableViewCellの高さを動的に変えるのって大変なのかなーと思っていたけれど
ちゃんと整理してみたらとても簡単にできました。