[iOS][XCODE][UITableView]TableViewCellの高さを計算して調整する方法

UITableViewCellの高さを自動調整するには、
UITableViewのrowHeightプロパティに[UITableViewAutomaticDimensionを設定する方法](http://qiita.com/nakamurau1@github/items/e1432086991bc3733c06)がある。

だけど、この方法を使うにはTableView内の全てのセルにAutoLayoutが不足なく設定されていなければならない。
しかしレガシーなアプリだと、AutoLayoutが設定されていないものもあり、すべてのセルに対して設定し直すというのは面倒。
そんな時は、次のようにtableView:heightForRowAtメソッドで内容によって高さを調整したいセルの高さを計算して返す。

```swift
import UIKit

//各TableViewCellのIdentifier
private let topCellID = "topCellID"
private let middleCellID = "middleCellID"
private let bottomCellID = "bottomCellID"

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var mainTable: UITableView!
    
    static let cellIDs: [String] = [topCellID, middleCellID, bottomCellID]
    
    var cellTexts: [String: String] = [:]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        mainTable.delegate = self
        mainTable.dataSource = self
        
        cellTexts[topCellID] = self.reapeatChar(targetChar: "上", repeatNum: 100) + "終"
        cellTexts[middleCellID] = self.reapeatChar(targetChar: "中", repeatNum: 200) + "終"
        cellTexts[bottomCellID] = self.reapeatChar(targetChar: "下", repeatNum: 300) + "終"
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // 行数
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return ViewController.cellIDs.count
    }
    
    // セルの高さ
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let cellId: String = ViewController.cellIDs[indexPath.row]
        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellId)!
        
        if [topCellID, middleCellID, bottomCellID].contains(cellId) {
            return self.getCellHeight(tableView: tableView, text: self.cellTexts[cellId]!)
        }
        
        return cell.bounds.height
    }
    
    // セルの中身
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellId: String = ViewController.cellIDs[indexPath.row]
        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellId)!
        
        if cellId == topCellID {
            let label = cell.viewWithTag(100) as! UILabel
            label.text = cellTexts[cellId]
        } else if cellId == middleCellID {
            let label = cell.viewWithTag(100) as! UILabel
            label.text = cellTexts[cellId]
        } else if cellId == bottomCellID {
            let label = cell.viewWithTag(100) as! UILabel
            label.text = cellTexts[cellId]
        }
    
        return cell
    }
    
    // セクション数
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    // セルの高さを返す
    private func getCellHeight(tableView: UITableView, text: String) -> CGFloat {
        
        let maxMessageLabelWidth: CGFloat = UIScreen.main.bounds.size.width
        let messageLabelHeight: CGFloat = self.getLabelSize(text: text, font: UIFont.systemFont(ofSize: 13.0), width: maxMessageLabelWidth, height: CGFloat.greatestFiniteMagnitude).height
        
        return messageLabelHeight + 16 //ラベルの上下には間隔が空くので16ptほど余分に高さを設定
    }
    
    // 高さと幅を計算するメソッド
    private func getLabelSize(text: String, font: UIFont, width: CGFloat, height: CGFloat) -> CGSize {
        let maxSize: CGSize = CGSize(width: width, height: height)
        let attr = [NSFontAttributeName: font]
        
        let size: CGSize = text.boundingRect(with: maxSize,
                                             options: [NSStringDrawingOptions.usesLineFragmentOrigin, NSStringDrawingOptions.truncatesLastVisibleLine],
                                             attributes: attr,
                                             context: nil).size
        return size
    }
    
    private func reapeatChar(targetChar: String, repeatNum: Int) -> String {
        var resStr: String = ""
        for _ in 1 ... repeatNum {
            resStr += targetChar
        }
        return resStr
    }
}
```