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

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

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

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

Swift

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

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

Q&A

解決済

1回答

1795閲覧

他のViewControllerからTableViewにセルを追加したい

y_ina

総合スコア14

Xcode

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

Swift

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

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

0グッド

0クリップ

投稿2018/03/16 05:20

私は今iphoneアプリの作成の勉強をしています。「本気で始めるiPhoneアプリ作り Xcode 9.x + Swift4.x対応」という書籍にTableviewを用いたTodoリストアプリのサンプルがありました。サンプルでは右上の+ボタンを押すとAlertが現れて、そこに文字列を入力することでToDoを登録するという方式をとっていました。これをアラートではなく、次の画面に遷移して、次の画面のtextFieldに文字を入力して登録ボタンを押すことによってTodoを登録できるようにしたかったのですが、Fatal errorが出てアプリが落ちてしまいました。どうしたらいいですか?
イメージ説明

swift

1import UIKit 2 3class NextViewController: UIViewController { 4 5 @IBOutlet weak var textBox: UITextField! 6 override func viewDidLoad() { 7 super.viewDidLoad() 8 9 // Do any additional setup after loading the view. 10 } 11 12 override func didReceiveMemoryWarning() { 13 super.didReceiveMemoryWarning() 14 // Dispose of any resources that can be recreated. 15 } 16 17 @IBAction func tapButton(_ sender: Any) { 18 let myTodo = MyTodo() 19 myTodo.todoTitle = textBox.text! 20 let firstVC = self.storyboard?.instantiateViewController(withIdentifier: "firstView") as! ViewController 21 firstVC.todoList.insert(myTodo, at: 0) 22 // テーブルに行が追加されたことをテーブルに通知 23 firstVC.tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.right) 24 25 } 26}

swift

1import UIKit 2 3class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { 4 5 // ToDoを格納した配列 6 var todoList = [MyTodo]() 7 8 @IBOutlet weak var tableView: UITableView! 9 10 override func viewDidLoad() { 11 super.viewDidLoad() 12 // Do any additional setup after loading the view, typically from a nib. 13 // 保存しているToDoの読み込み処理 14 let userDefaults = UserDefaults.standard 15 if let storedTodoList = userDefaults.object(forKey: "todoList") as? Data { 16 if let unarchiveTodlList = NSKeyedUnarchiver.unarchiveObject(with: storedTodoList) as? [MyTodo] { 17 todoList.append(contentsOf: unarchiveTodlList) 18 } 19 } 20 } 21 22 override func didReceiveMemoryWarning() { 23 super.didReceiveMemoryWarning() 24 // Dispose of any resources that can be recreated. 25 } 26 27 // もともとの+ボタンを押した際の処理 28// @IBAction func tapAddButton(_ sender: Any) { 29// // アラートダイアログを生成 30// let alertController = UIAlertController(title: "TODO追加", message: "TODOを入力してください", preferredStyle: UIAlertControllerStyle.alert) 31// // テキストエリアを追加 32// alertController.addTextField(configurationHandler: nil) 33// 34// // OKボタンがタップされた時の処理 35// let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) { (action: UIAlertAction) in 36// // OKボタンがタップされた時の処理 37// if let textField = alertController.textFields?.first { 38// // ToDoの配列に入力値を挿入。先頭に挿入する 39// let myTodo = MyTodo() 40// myTodo.todoTitle = textField.text! 41// self.todoList.insert(myTodo, at: 0) 42// 43// // テーブルに行が追加されたことをテーブルに通知 44// self.tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.right) 45// 46// // ToDoの保存処理 47// let userDefaults = UserDefaults.standard 48// // Data型にシリアライズする 49// let data = NSKeyedArchiver.archivedData(withRootObject: self.todoList) 50// userDefaults.set(data, forKey: "todoList") 51// userDefaults.synchronize() 52// } 53// } 54// 55// // OKボタンを追加 56// alertController.addAction(okAction) 57// 58// // CANCELボタンがタップされた時の処理 59// let cancelButton = UIAlertAction(title: "CANCEL", style: UIAlertActionStyle.cancel, handler: nil) 60// // CANCELボタンを追加 61// alertController.addAction(cancelButton) 62// 63// // アラートダイアログを表示 64// present(alertController, animated: true, completion: nil) 65// } 66 67 // テーブルの行数を返却する 68 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 69 // ToDoの配列の長さを返却する 70 return todoList.count 71 } 72 73 // テーブルの行ごとのセルを返却する 74 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 75 // Storyboardで指定したtodoCell識別子を利用して再利用可能なセルを取得する 76 let cell = tableView.dequeueReusableCell(withIdentifier: "todoCell", for: indexPath) 77 78 // 行番号に合ったToDoの情報を取得 79 let myTodo = todoList[indexPath.row] 80 // セルのラベルにToDoのタイトルをセット 81 cell.textLabel?.text = myTodo.todoTitle 82 // セルのチェックマーク状態をセット 83 if myTodo.todoDone { 84 // チェックあり 85 cell.accessoryType = UITableViewCellAccessoryType.checkmark 86 } else { 87 // チェックなし 88 cell.accessoryType = UITableViewCellAccessoryType.none 89 } 90 return cell 91 } 92 93 // セルをタップした時の処理 94 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 95 let myTodo = todoList[indexPath.row] 96 if myTodo.todoDone { 97 // 完了済みの場合は未完了に変更 98 myTodo.todoDone = false 99 } else { 100 // 未完の場合は完了済みに変更 101 myTodo.todoDone = true 102 } 103 104 // セルの状態を変更 105 tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.fade) 106 // データ保存。Data型にシリアライズする 107 let data: Data = NSKeyedArchiver.archivedData(withRootObject: todoList) 108 // UserDefautlsに保存 109 let userDefaults = UserDefaults.standard 110 userDefaults.set(data, forKey: "todoList") 111 userDefaults.synchronize() 112 } 113 114 // セルが編集可能であるかどうかを返却する 115 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 116 return true 117 } 118 119 // セルを削除した時の処理 120 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 121 // 削除処理かどうか 122 if editingStyle == UITableViewCellEditingStyle.delete { 123 // ToDoリストから削除 124 todoList.remove(at: indexPath.row) 125 // セルを削除 126 tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.fade) 127 // データ保存。Data型にシリアライズする 128 let data: Data = NSKeyedArchiver.archivedData(withRootObject: todoList) 129 // UserDefautlsに保存 130 let userDefaults = UserDefaults.standard 131 userDefaults.set(data, forKey: "todoList") 132 userDefaults.synchronize() 133 } 134 } 135} 136 137// 独自クラスをシリアライズする際には、NSObjectを継承し 138// NSCodingプロトコルに準拠する必要がある 139class MyTodo: NSObject, NSCoding { 140 // ToDoのタイトル 141 var todoTitle: String? 142 // ToDoを完了したかどうかを表すフラグ 143 var todoDone: Bool = false 144 // コンストラクタ 145 override init() { 146 147 } 148 149 // NSCodingプロトコルに宣言されているデシリアライズ処理。デコード処理とも呼ばれる 150 required init?(coder aDecoder: NSCoder) { 151 todoTitle = aDecoder.decodeObject(forKey: "todoTitle") as? String 152 todoDone = aDecoder.decodeBool(forKey: "todoDone") 153 } 154 155 // NSCodingプロトコルに宣言されているシリアライズ処理。エンコード処理とも呼ばれる 156 func encode(with aCoder: NSCoder) { 157 aCoder.encode(todoTitle, forKey: "todoTitle") 158 aCoder.encode(todoDone, forKey: "todoDone") 159 } 160} 161

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

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

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

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

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

guest

回答1

0

ベストアンサー

View間で他のViewのテーブルを操作するのではなく、
登録画面で、UserDefaultに追加を終えてしまい、
View移動させる、
移動が完了したら、一覧ビューを更新、
という流れの方がすぐ動かせると思いますし、簡単だと思います。

投稿2018/03/16 05:39

miyabi_takatsuk

総合スコア9528

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

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

y_ina

2018/03/16 06:21

回答ありがとうございます とりあえず以下のようにNextViewControllerのtapButtonメソッドを書き換えてみました。 tableViewの更新やViewの遷移についてはまだ実装していませんが、これでアプリを実行して文字を入力してボタンを押してアプリを閉じてもう一回開きなおすととりあえず文字が入ってることが確認できました。しかし、二つ目や三つ目のTodoを登録しようとしてみても、アプリを開き直した際に、最後に登録した一個しか登録されていない状態なのですがどうしたら良いでしょうか? @IBAction func tapButton(_ sender: Any) { let myTodo = MyTodo() myTodo.todoTitle = textBox.text! let firstVC = self.storyboard?.instantiateViewController(withIdentifier: "firstView") as! ViewController firstVC.todoList.insert(myTodo, at: 0) let userDefaults = UserDefaults.standard let data = NSKeyedArchiver.archivedData(withRootObject: firstVC.todoList) userDefaults.set(data, forKey: "todoList") userDefaults.synchronize() }
miyabi_takatsuk

2018/03/16 07:02 編集

そりゃそうですよ。 UserDefaultsで使用しているデータは一個なんですから。 そのまま、UserDefaultsを使って作るなら、 ToDoのデータ自体は、配列として扱い、 配列に、新たなデータを追加、 UserDefaultsに登録するときは、 配列を文字列に変換し、登録。 取り出すときは、 UserDefaultsから文字列として取り出し、 配列に変換、操作・・・。 って感じですかね。 おそらくよくわからないと思うので、、、 もっとToDoアプリっぽくしっかりやりたい、とお思いなら、 CoreDataなどの、アプリ内データベースで、 データの取り扱いするとやりやすいと思いますよ。
y_ina

2018/03/16 08:03

丁寧にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問