Swift4,Xcode10対応：プログラミング初心者でも簡単に作れるRealmとFSCalendarを用いた日記アプリ作成（２）

#プログラミング初心者でも簡単に作れるRealmとFSCalendarを用いた日記アプリ作成（２）

-環境-
・Xcode10
・Swift4

前回はパーツの配置まで行いました。
[プログラミング初心者でも簡単に作れるRealmとFSCalendarを用いた日記アプリ作成（１）](https://qiita.com/atsushi_takao/items/a824e9cc4e97cafb470f)

今回は、コードを書いていきます。

##3-3 コードを書く
ここからコードを書いていきます。
最初は写経で大丈夫です。

###3-3-0 コードを書くためのファイルを作成する。
ファイルの作成の仕方は以下の手順です。

既にファイルがある場所（Xcodeの左側）で右クリック
→「New File」を選択
→「Cocoa Touch Class」を選択

以上の手順をすると以下の画像が出るはずです。

<img width="731" alt="スクリーンショット 2019-02-10 21.41.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/189993/944c814a-cfe8-33e2-98c4-c154ef6dbaf5.png">

ここでClassとSubClassを指定します。
初めは
**Class：CalendarViewController**
**SubClass：UIViewController**
とします。

これがCalendarを表示する画面を制御するファイルです。

上記の手順で以下のファイルも作ってください。

②日記のモデル
**Class：Diary**
**SubClass：NSObject**

③追加画面を制御するファイル
**Class： AddDiaryViewController**
**SubClass：UIViewController**

④詳細画面を制御するファイル
**Class：DetailDairyViewController**
**SubClass：UIViewController**

⑤アラート表示のためのファイル
**Class: SimpleAlert**
**SubClass: NSObject**

###3-3-1 日記のモデルのコードを書く。

```ruby:Diary.swift
import UIKit
import Realm
import RealmSwift

class Diary: Object {
    
    static let realm = try! Realm()
    
    //Diaryのプロパティを定義
    @objc dynamic private var id = 0
    @objc dynamic var date: String = ""
    @objc dynamic var title: String = ""
    @objc dynamic var note: String = ""
    
    //キーの設定
    override static func primaryKey() -> String? {
        return "id"
    }
    
    //新規作成
    static func create() -> Diary {
        let diary = Diary()
        diary.id = lastId()
        return diary
    }
    
    //日付指定で読み込み
    static func search(date: Date) -> [Diary] {
        let selectedDay = Diary.changeDateType(date: date)
        let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { migration, oldSchemaVersion in
                if (oldSchemaVersion < 1) {
                }
        })
        Realm.Configuration.defaultConfiguration = config
        if realm.objects(Diary.self).filter("date == '\(selectedDay)'").isEmpty == false {
            let objects = realm.objects(Diary.self).filter("date == '\(selectedDay)'")
            var diaryArray: [Diary] = []
            for object in objects {
                diaryArray.append(object)
            }
            return diaryArray
        } else {
            return []
        }
        
    }
    
    //Idの設定
    static func lastId() -> Int {
        if let object = realm.objects(Diary.self).last {
            return object.id + 1
        } else {
            return 1
        }
    }
    
    //保存
    func save() {
        try! Diary.realm.write {
            Diary.realm.add(self)
        }
    }
    
    //日付のフォーマット指定
    static func changeDateType(date: Date) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM月dd日"
        let text = dateFormatter.string(from: date)
        return text
    }
    
    

}
```

###3-3-2 CalendarViewControllerのコードを書く。

```ruby:CalendarViewController.swift

import UIKit
import FSCalendar
import Realm
import RealmSwift

class CalendarViewController: UIViewController {

    var diaryArray: [Diary] = []
    
    @IBOutlet weak var calendar: FSCalendar!
    @IBOutlet weak var diaryTitleTableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        calendar.delegate = self
        calendar.dataSource = self
        
        configureTableView()
        
        diaryArray = Diary.search(date: Date())
        
    }
    
    override func viewWillAppear(_ animated: Bool) {
        diaryArray = Diary.search(date: Date())
        diaryTitleTableView.reloadData()
    }
    
   
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toDetail" {
            let detailDiaryViewController = segue.destination as! DetailDairyViewController
            let selectedIndex = diaryTitleTableView.indexPathForSelectedRow!
            detailDiaryViewController.selectedDiary = diaryArray[selectedIndex.row]
        }
    }
    
    // Private
    func configureTableView() {
        //dataSourceとdelegateメソッドが使えるように。
        diaryTitleTableView.delegate = self
        diaryTitleTableView.dataSource = self
        
        //セルの高さを30.0で固定
        diaryTitleTableView.rowHeight = 30.0
        
        //余白を消す
        diaryTitleTableView.tableFooterView = UIView()
    }
    
    
}

extension CalendarViewController: UITableViewDelegate, UITableViewDataSource {
    
    // MARK: - TableView DataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return diaryArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "diaryCell")!
        
        cell.textLabel?.text = diaryArray[indexPath.row].title
        
        return cell
    }
    
    // MARK: - TableView Delegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // 詳細画面に遷移
        self.performSegue(withIdentifier: "toDetail", sender: nil)
    }
}


extension CalendarViewController: FSCalendarDataSource, FSCalendarDelegate {
    // MARK: - FSCalendar Delegate
    func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
        //日付選択時に呼ばれるメソッド
        diaryArray = Diary.search(date: date)
        diaryTitleTableView.reloadData()
        
    }

}
```

###3-3-3 AddDiaryViewControllerのコードを書く。

```ruby:AddDiaryViewController.swift
import UIKit

class AddDiaryViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {

    @IBOutlet weak var titleTexitField: UITextField!
    @IBOutlet weak var detailTextView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        titleTexitField.delegate = self
        detailTextView.delegate = self

    }
   
    
    // MARK: - TextField Delegate
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    
    // MARK: - TextView Delegate
    func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
        textView.resignFirstResponder()
        return true
    }
    
    @IBAction func save() {
        if titleTexitField.text != "" {
            if detailTextView.text != "" {
                let newDiary = Diary.create()
                newDiary.title = titleTexitField.text!
                newDiary.note = detailTextView.text
                let today = Diary.changeDateType(date: Date())
                newDiary.date = today
                newDiary.save()
                self.navigationController?.popViewController(animated: true)
            } else {
                SimpleAlert.showAlert(viewController: self, title: "日記なし", message: "内容を描いてください", buttonTitle: "OK")
            }
        } else {
            SimpleAlert.showAlert(viewController: self, title: "タイトルなし", message: "タイトルを書いてください", buttonTitle: "OK")
        }
        
    }
    
}

```

###3-3-4 DetailDiaryViewControllerのコードを書く。

```ruby:DetailDiaryViewController.swift

import UIKit

class DetailDairyViewController: UIViewController {
    
    var selectedDiary = Diary()
    
    @IBOutlet weak var detailTextView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.navigationController?.title = "\(selectedDiary.title)"
        detailTextView.text = selectedDiary.note
    }
    

}

```

###3-3-5 SimpleAlert.swiftにコードを書く

```ruby:SimpleAlert.swift
import UIKit

struct SimpleAlert {
    static func showAlert(viewController: UIViewController, title: String, message: String, buttonTitle: String) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        let okAction = UIAlertAction(title: buttonTitle, style: .default) { (action) in
            alert.dismiss(animated: true, completion: nil)
        }
        alert.addAction(okAction)
        viewController.present(alert, animated: true, completion: nil)
    }
    
}
```

##3-4 関連付け

###3-4-1 コードと画面を繋ぐ

以下の画像を見ながら、それぞれの画面のClassを指定しましょう。

①カレンダーを閲覧する画面
**Class： CalendarViewController**

②追加画面
**Class： AddDiaryViewController**

③詳細画面
**Class：DetailDairyViewController**

<img width="1395" alt="スクリーンショット 2019-02-10 21.52.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/189993/451dbf05-7c63-ebc0-8398-3496aa9929be.png">


###3-4-2 パーツを関連付け

それぞれのパーツを以下の画像の要領で関連付けしましょう。

<img width="1398" alt="スクリーンショット 2019-02-10 21.58.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/189993/2bcc7d2f-d58a-3eb2-d4fd-29d2e22dda48.png">

関連付けするパーツは以下の通りです。

①カレンダーを閲覧する画面
**outlets: calendar, diaryTitleTableView**

②追加画面
**outlets: titleTexitField, detailTextView**
**actions: save**

③詳細画面
**outlets: detailTextView**

##4 デバッグする

ここまでできれば、あとは動くかどうかチェックしてみましょう！
動かない場合は見返してみましょう。

[プログラミング初心者でも簡単に作れるRealmとFSCalendarを用いた日記アプリ作成（１）](https://qiita.com/atsushi_takao/items/a824e9cc4e97cafb470f)

##GithubURL

今回のアプリを以下のリンクからダウンロードできます。
https://github.com/atsutko/Diary