質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1333閲覧

tableViewで表示されている項目の並び替えの不具合について realm

tyu

総合スコア17

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/02/14 23:47

【現在作成中のアプリの概要】

TODOリストのアプリを作成しています。
データの永続化には『realm』を使用しています。

realmに記録するデータは下記のToDoModel.swiftに記載しています。

【現在詰まっている箇所】

下記ページの内容の続きで、新規のToDoを書き込むごとにorder に常に最新で最大の番号を与えるようにしなければならないのですが、どのように実装したら良いかというところで詰まっています。

リンク内容

上記の実装を可能にする方法を知っている方がいらっしゃいましたら、ご教授の程よろしくお願い致します。

swift

1import UIKit 2import RealmSwift 3 4class ViewController: UIViewController,UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource { 5 6 @IBOutlet weak var todoTableView: UITableView! 7 8 var itemList: Results<TodoModel>! 9 10 override func viewDidLoad() { 11 super.viewDidLoad() 12 13 let realmInstance = try! Realm() 14 self.itemList = realmInstance.objects(TodoModel.self).sorted(byKeyPath: "order") 15 16 //更新 17 self.todoTableView.reloadData() 18 19 20 // UITableViewDataSource を self に設定 21 self.todoTableView.dataSource = self 22 // UITableViewDelegate を self に設定 23 self.todoTableView.delegate = self 24 25 26 27 //常時編集状態にする(isEditing,allowsSelectionDuringEditing) 28// todoTableView.isEditing = true 29 todoTableView.isEditing = false 30 todoTableView.allowsSelectionDuringEditing = true 31 32 // trueで複数選択、falseで単一選択 33 todoTableView.allowsMultipleSelection = true 34 35 } 36 // Add ボタンをクリックした際に実行する処理 37 //セルに文字を入力する 38 @IBAction func tapAddButton(_ sender: Any) { 39 40 var textField = UITextField() 41 // ① UIAlertControllerクラスのインスタンスを生成 参照サイト(https://qiita.com/funacchi/items/b76e62eb82fc8d788da5) 42 let alert = UIAlertController(title: "タスクを追加", message: "", preferredStyle: .alert) 43 // ② Actionの設定 44 let action = UIAlertAction(title: "追加する", style: .default) { (action) in 45 let instancedTodoModel:TodoModel = TodoModel() 46 instancedTodoModel.todo = textField.text 47 48 print(instancedTodoModel) 49 let realmInstance = try! Realm() 50 try! realmInstance.write{ 51 realmInstance.add(instancedTodoModel) 52 } 53 self.todoTableView.reloadData() 54 } 55 56 alert.addTextField { (alertTextField) in 57 alertTextField.placeholder = "タスクを入力" 58 textField = alertTextField 59 } 60 // キャンセルボタンの追加 61 let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertAction.Style.cancel, handler:{ 62 // ボタンが押された時の処理を書く(クロージャ実装) 63 (action: UIAlertAction!) -> Void in 64 print("Cancel") 65 }) 66 // ③ UIAlertControllerにActionを追加 67 alert.addAction(cancelAction) 68 alert.addAction(action) 69 present(alert, animated: true, completion: nil) 70 71 } 72 // Remove All ボタンをクリックした際に実行する処理 73 //セルに表示されている文字をすべて削除する 74 @IBAction func tapRemoveAllButton(_ sender: Any) { 75 let realmInstance = try! Realm() 76 try! realmInstance.write{ 77 //↓以下のコードを有効にするとrealmに記録しているすべてのデータが消えてしまう 78// realmInstance1.deleteAll() 79 //↑上記のコードだとrealmに記録しているすべてのデータが消えてしまうため下記のコードに書き換えた↓ 80 realmInstance.delete(itemList) 81 } 82 self.todoTableView.reloadData() 83 } 84 85 //セルの編集モードをONにする 86 @IBAction func edit(_ sender: Any) { 87 todoTableView.isEditing = true 88 } 89 90 // セルが選択された時に呼び出される 91 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 92 print("セル(indexPath)が選択されました") 93 //テーブルビューのセルをクリックしたら、アラートコントローラを表示 94// showAlertController(indexPath) 95 let item: TodoModel = self.itemList[(indexPath as NSIndexPath).row] 96 97 98 // Realm に保存したデータを UIAlertController に入力されたデータで更新 99 let realmInstance = try! Realm() 100 try! realmInstance.write{ 101 item.done = !item.done 102 103 } 104 105 // リロードしてUIに反映 106 self.todoTableView.reloadData() 107 } 108 109 //セルの選択が外れた時に呼び出される 110 func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { 111 112 } 113 114 func numberOfSectionsInTableView(tableView: UITableView) -> Int { 115 return 1 116 } 117 //セルの数を返す 118 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 119 return self.itemList.count 120 } 121 122 //必須メソッド_埋め込むセルの値を設定 123 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 124 125 let testCell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "testCell")! 126 let item: TodoModel = self.itemList[(indexPath as NSIndexPath).row] 127 testCell.textLabel?.text = item.todo 128 //チェックマークを表示する処理ーitemのdoneがtrueだったら表示falseだったら非表示 129 testCell.accessoryType = item.done ? .checkmark : .none 130 return testCell 131 } 132 //並べ替え可能にするメソッド 133 func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { 134 return true 135 } 136 137 //realmでtableviewのセルを並び替えるメソッド(https://ja.stackoverflow.com/questions/35653/realmをデータソースにしてテーブルビューの並べ替えをしたい) 138 //並べ替え結果を処理するメソッド 139 func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { 140 // TODO: 入れ替え時の処理を実装する(データ制御など) 141 print("並び替え開始") 142 let realmInstance = try! Realm() 143 try! realmInstance.write{ 144 let sourceObject = itemList[sourceIndexPath.row] 145 print("最初の行",sourceObject.order) 146 let destinationObject = itemList[destinationIndexPath.row] 147 148 let destinationObjectOrder = destinationObject.order 149 150 151 if sourceIndexPath.row < destinationIndexPath.row { 152 // 上から下に移動した場合、間の項目を上にシフト 153 for index in sourceIndexPath.row...destinationIndexPath.row { 154 let object = itemList[index] 155 object.order -= 1 156 } 157 } else { 158 // 下から上に移動した場合、間の項目を下にシフト 159 for index in (destinationIndexPath.row..<sourceIndexPath.row).reversed() { 160 let object = itemList[index] 161 object.order += 1 162 } 163 } 164 // 移動したセルの並びを移動先に更新 165 sourceObject.order = destinationObjectOrder 166 print("最後の行",sourceObject.order) 167// self.todoTableView.reloadData() 168 } 169 170 } 171 172 //以下のコードを追加すると削除モードが表示されなくなる(editingStyleForRowAt,shouldIndentWhileEditingRowAt) 173 //編集状態の見た目を編集(左側の+やーを表示)これを消すとマイナスボタンが表示される 174// func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { 175// return .none //表示させない。 176// } 177 178 179 //編集モード時に左にずれるか。 180 func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool { 181// return false//ずれない。 182 return true//ずれる 183 } 184 185// テーブルビューの編集を許可 186 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 187 return true 188 } 189 190 // テーブルビューのセルとデータを削除 191 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 192 if editingStyle == UITableViewCell.EditingStyle.delete { 193 // データを削除 194 let realmInstance = try! Realm() 195 try! realmInstance.write { 196 realmInstance.delete(itemList[indexPath.row]) 197 } 198 // セルを削除 199 tableView.deleteRows(at: [indexPath as IndexPath], with: UITableView.RowAnimation.automatic) 200 } 201 } 202 203 204 //テーブルビューのセルをクリックしたら、アラートコントローラを表示する処理 205 func showAlertController(_ indexPath: IndexPath){ 206 let alertController: UIAlertController = UIAlertController(title: "ToDo を編集", message: "", preferredStyle: .alert) 207 // アラートコントローラにテキストフィールドを表示 テキストフィールドには入力された情報を表示させておく処理 208 alertController.addTextField(configurationHandler: {(textField: UITextField!) in 209 textField.text = self.itemList[indexPath.row].todo}) 210 211 // アラートコントローラに"OK"ボタンを表示 "OK"ボタンをクリックした際に、テキストフィールドに入力した文字で更新する処理を実装 212 alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { 213 (action) -> Void in self.updateAlertControllerText(alertController,indexPath) 214 })) 215 // アラートコントローラに"Cancel"ボタンを表示 216 alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) 217 self.present(alertController, animated: true, completion: nil) 218 219 //removeTask 220 } 221 222 // "OK"ボタンをクリックした際に、テキストフィールドに入力した文字で更新 223 func updateAlertControllerText(_ alertcontroller:UIAlertController, _ indexPath: IndexPath) { 224 // guard を利用して、nil チェック 225 guard let textFields = alertcontroller.textFields else {return} 226 guard let text = textFields[0].text else {return} 227 228 // UIAlertController に入力された文字をコンソールに出力 229 print(text) 230 231 // Realm に保存したデータを UIAlertController に入力されたデータで更新 232 let realmInstance = try! Realm() 233 try! realmInstance.write{ 234 itemList[indexPath.row].todo = text 235 } 236 self.todoTableView.reloadData() 237 } 238} 239

swift

1import Foundation 2import RealmSwift 3 4class TodoModel: Object{ 5 @objc dynamic var todo: String? = nil 6 @objc dynamic var order: Int = 0 // 並べ替えのためのカラムが必要 7 @objc dynamic var done: Bool = false 8 9} 10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/02/15 00:16

itemList が order でソート済みなら、その末尾の項目の order が最大のはずですから、それに + 1 すればいいのでは。
guest

回答1

0

ベストアンサー

コメント欄でhoshi-takanoriさんご指摘の通りです。

一方、具体的に実装するとなると、itemList が空配列の場合もあるため、次のような感じで実装することになると思います。

空配列の場合は self.itemList.lastnil となるため、続くブロックは実行されません。
一方、TodoModel()はデフォルト値として order = 0 となっているため、空配列の場合には順番は 0 から再開されます。

Swift

1 let action = UIAlertAction(title: "追加する", style: .default) { (action) in 2 let instancedTodoModel = TodoModel() 3 instancedTodoModel.todo = textField.text 4 5 // MARK: order をインクリメントする 6 if let lastItem = self.itemList.last { 7 instancedTodoModel.order = lastItem.order + 1 8 } 9 10 let realmInstance = try! Realm() 11 12 try! realmInstance.write { 13 realmInstance.add(instancedTodoModel) 14 } 15 16 self.todoTableView.reloadData() 17 }

投稿2021/02/15 03:07

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tyu

2021/02/15 15:06

TsukubaDepotさん、hoshi-takanoriさん、ご教授いただきありがとうございます。 希望していた昨日の実装ができました。 お二人のように自力で解決できるように今回の内容を復習してみます。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問