寒川アクアブログ

美容師しながらアプリ開発していて水草が趣味の私のブログです

【Swift4】ToDoリストアプリを作る(4)

新規タスクを追加するところまで実装できました。
セルのテキストビューをタップするとテキストの編集はできますが、キーボードが閉じないので、編集が終わったらキーボードを閉じる処理をまずは実装します。

ソフトキーボードの「改行」表示を「Done」に変更

ストーリーボード上でセルのTextViewを選択し、Text Input TraitsのReturn KeyをDoneに変更します。
キーボードの改行ボタンの表示がDoneに変更されました。

テキストの編集を逐一監視し、改行だったらキーボードを閉じる

class TableViewCell: UITableViewCell,UITextViewDelegate {    //    ←追加

 //    略

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        
        if text == "\n" {
            textView.resignFirstResponder()    //    キーボードを閉じる
                    return false
        }
        return true
    }

テキストの変更を監視し、改行キーが押されたらキーボードを閉じる処理をしています。

Taskの変更を保存する

セルの方でTaskのインスタンスを保持し、テキストの編集やチェックボックスの変更があった時にインスタンスに変更を反映させます。その最新状態のインスタンスをTableViewControllerへ渡し、CoreDataに保存するという流れです。

import UIKit

//    セルの変更があった時にテーブルビューへ伝えるメソッド
protocol CellDelegate {
    func didTaskChenge(task:Task,isTextChanged:Bool)
}

class TableViewCell: UITableViewCell,UITextViewDelegate {

    @IBOutlet weak var checkBox: CheckBox!
    @IBOutlet weak var textView: UITextView!
    
    var task:Task!    //    Taskのインスタンスを保持
    var delegate:CellDelegate!    //    デリゲート
    
    override func awakeFromNib() {
        super.awakeFromNib()
        textView.delegate = self
    }
    
    //    TableViewから実行する初期化のためのメソッドを定義
    func dataInit( _ task:Task){
        self.task = task
        checkBox.setChecked(task.isChecked)
        textView.text = task.text
    }
    
    //    テキストビューのデータソース

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if text == "\n" {
            textView.resignFirstResponder() //キーボードを閉じる
            return false
        }
        return true
    }
    
    //    編集が終了したタイミング
    func textViewDidEndEditing(_ textView: UITextView) {
        print("エディット終了")
        task.text = textView.text    //    インスタンスに変更を加えて
        delegate.didTaskChenge(task: task, isTextChanged: true)    //    TableViewControllerに送る
    }
    
 //    チェックボックスのタップイベント
    @IBAction func checkBoxTap(_ sender: CheckBox) {

        task.isChecked = !task.isChecked
        sender.setChecked(task.isChecked)    //    変更して
        delegate.didTaskChenge(task: task, isTextChanged: false)    //    TableViewControllerへ
    }


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

    }
}

TableViewController側のセルの初期化処理

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
        
        let task = tasks[indexPath.row]
        
        cell.dataInit(task)
        cell.delegate = self

        return cell
    }

cell.dataInit(task)を実行することで、テーブルビュー側では初期化処理をせず、セル側で行うようにします。

TableViewでセルの変更を受け取る

デリゲートを追加してコールバックを受け取り、セーブする処理を実装します。

class TableViewController: UITableViewController,CellDelegate{    //    ←追加

    //    セルからのコールバック
    func didTaskChenge(task: Task, isTextChanged: Bool) {
        if let index = tasks.index(where: {$0.dateUTC == task.dateUTC}){
            tasks[index] = task
            saveData()
        }

    }

tasks配列の中から、dateUTCをIDがわりに当該Taskのインデックスを取得して、セルから送られてきた最新状態のTaskを格納し、saveData()でCoreDataに保存しています。