【Swift4】Realm Databaseに格納したデータをカスタムセルに表示する

# 概要
Realm Databaseに格納したデータを取得し、カスタムセルに表示させる方法についての記事です。
Realm Databaseの使い方とカスタムセルの作り方を学んだので組み合わせてみました。

TableViewのセルじゃなくて好きな形のセルにデータを表示したい！といった方のお役に立てれば幸いです。

# 実行環境
【Xcode】 Version 10.1
【Swift】 version 4.2.1
【CocoaPods】version 1.6.0
【Realm Database】 3.13.1

# 実装
## Realm Databaseの導入
はじめにRealm Databaseを新規プロジェクトに導入します。Realm Databaseのインストール方法は下記記事が大変参考になりますのでこちらをご参照ください。
[【Swift】RealmSwiftをインストール(CocoaPods)から実行まで](https://qiita.com/leegun/items/70414223b2339b6052ee)

## Main.storyboard
Main.storyboardは下の画像のように実装します。
設置したものは以下の通りです。
ViewController
・Navigation Bar
・TableView
AddViewController
・Label
・TextField
・Button
<img width="893" alt="スクリーンショット 2019-02-16 20.19.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/347128/9cef611c-a965-c08a-6c06-a100301bd430.png">

## カスタムセル作成
続いてカスタムセルを作成していきます。
まずFile > New > File... から「Cocoa Touch Class」を新規作成します。
このとき、Subclass of:UITableViewCellを選択し、「Also create XIB file」にチェックをつけるようにします。
<img width="734" alt="スクリーンショット 2019-02-16 19.33.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/347128/073d430c-ef9d-23d5-4065-1745d166401f.png">

作成すると「TableViewCell.swift」と「TableViewCell.xib」の2つのファイルができます。

次に「TableViewCell.xib」でカスタムセルを作成していきます。
配置されているTableViewCellのWidthとHeightを設定し、セルの中にtextFieldやLabelなどを設置します。
今回はWidth：375、Height：125とし、以下のようにセルを作成しました。
<img width="402" alt="スクリーンショット 2019-02-16 20.07.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/347128/7b50e114-62ab-b161-3e2c-9b288efb2cbb.png">

セルを作り終わったら、「TableViewCell.swift」にセルに追加したLabelをOutlet接続します。

```swift:TableViewCell.swift
    // 商品名
    @IBOutlet weak var itemName: UILabel!
    // 数量
    @IBOutlet weak var itemNumber: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
```

これでカスタムセルの作成は完了です。

## TableViewに作成したカスタムセルを表示させる
作成したカスタムセルをTableViewに表示させるようにします。

```swift:ViewController.swift
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.delegate = self
        tableView.dataSource = self
        
        // tableViewにカスタムセルを登録
        tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // セルの内容を取得
        let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
        return cell
    }
```

## Realm Databaseに対するデータの追加、取得、削除
続いてRealm Databaseに対する処理を記述していきます。
まずは、モデルとなるItemクラスを作成します。
（File > New > File... > SwiftFileで作成）

```swift:Item.swift
import Foundation
import RealmSwift

class Item: Object {
    // 商品名
    @objc dynamic var itemName = ""
    // 数量
    @objc dynamic var itemNumber = ""
}
```

次にデータを追加する処理をAddViewControllerに記述していきます。

```swift:AddViewController.swift
import UIKit
import RealmSwift

class AddViewController: UIViewController {
    
    @IBOutlet weak var itemName: UITextField!
    @IBOutlet weak var itemNumber: UITextField!
    
    @IBAction func addButton(_ sender: Any) {
        // Itemクラスのインスタンス作成
        let newItem = Item()
        // TextFieldの値を代入
        newItem.itemName = itemName.text!
        newItem.itemNumber = itemNumber.text!
        
        // インスタンスをRealmに保存
        do{
            let realm = try Realm()
            try realm.write({ () -> Void in
                realm.add(newItem)
            })
        }catch{
        }
        // 画面を閉じる
        self.dismiss(animated: true,completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
```

最後にViewControllerクラスに追加したデータを表示する処理と削除する処理を追記します。

```swift:ViewController.swift

import UIKit
import RealmSwift

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var itemList: Results<Item>!
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.delegate = self
        tableView.dataSource = self
        
        // Realmからデータを取得
        do{
            let realm = try Realm()
            itemList = realm.objects(Item.self)
        }catch{
        }
        // tableViewにカスタムセルを登録
        tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
        tableView.tableFooterView = UIView()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return itemList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
        // カスタムセル内のプロパティ設定
        cell.itemName.text = itemList[indexPath.row].itemName
        cell.itemName.textAlignment = .center
        cell.itemName.adjustsFontSizeToFitWidth = true
        cell.itemNumber.text = itemList[indexPath.row].itemNumber
        cell.itemNumber.textAlignment = .center
        cell.itemNumber.adjustsFontSizeToFitWidth = true
        
        return cell
    }

    // セルの削除
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath){
        if(editingStyle == UITableViewCell.EditingStyle.delete) {
            // Realm内のデータを削除
            do{
                let realm = try Realm()
                try realm.write {
                    realm.delete(self.itemList[indexPath.row])
                }
                tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.fade)
            }catch{
            }
        }
    }
}
```

最後に、TableViewのreload処理とセルの高さを設定すれば完成です！

```swift:ViewController.swift
let cellHeigh:CGFloat = 125

    // 画面が表示される直前にtableViewを更新
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData()
    }

    // セルの高さを設定
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return cellHeigh
    }
```

# 完成したもの
![qiita2.gif](https://qiita-image-store.s3.amazonaws.com/0/347128/0bf517eb-7827-e338-f3ed-a39f3bee3a5f.gif)
基本と基本を組み合わせただけですが、いい感じになりました！
全体のソースコードは[GitHub](https://github.com/naipaka/CustomCellByRealm)にあげていますのでご参照ください！

# 参考
以下の記事を参考にさせていただきました。:bow:
・[Swift カスタムセルを再利用したtableViewの作り方 [初級向け]](https://qiita.com/TD3P/items/116a2199b1f872ac6471)
・[RealmSwiftとUITableViewを使用してToDoアプリを作成](https://qiita.com/TsukasaHasegawa/items/4dfaa87add7b6866f858)