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

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

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

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

Q&A

解決済

2回答

3471閲覧

swiftで日記アプリを作成したい。画面遷移の値渡しや、日記の編集ができなくて困っています。

Daisuke0315

総合スコア23

Swift

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

0グッド

1クリップ

投稿2020/04/09 04:40

編集2020/04/10 01:17

◇環境
【Xcode】11.4【macOS】 Catalina 10.15.4【Swift】5.2【iOS】13.3.1

◇実現したいこと
tableviewを用いた日記アプリの作成

TableViewのセルをタップした時に、別画面に遷移させたい。(←できました)
遷移させる際にセルの情報を取得したい。(←できません)
編集した情報を上書きする(←見当がつきません)

◇実行したこと(参考にしたHP)
https://qiita.com/pe-ta/items/8f474358d1dd789557f3
このページを参考にしてuserdefaultを用いたテーブルを作成しました

https://teratail.com/questions/219454
このページを参考にしてcellをタップして画面遷移・値渡しのコードを作成しました

ストーリーボードの画像です

◇実行したコマンド、エラーログ

ここでCannot force unwrap value of non-optional type 'String'のエラーログが出てしまうのですが改善方法がわかりません。

swift

1 //画面遷移後に値渡しを行う 2 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 3 let watasi:AddViewController = (segue.destination as? AddViewController)! 4 watasi.watasitext = selectedtext! 5 }

日記のリスト画面の制御コードです

swift

1 2 3import UIKit 4 5class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource { 6 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 7 nikkinaiyou.count 8 } 9 10 //セルの再利用とリストに表示するアクション 11 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 12 let nikkicell = tableView.dequeueReusableCell(withIdentifier: "nikkicell", for: indexPath) 13 nikkicell.textLabel!.text = nikkinaiyou[indexPath.row] 14 return nikkicell 15 } 16 17 var selectedtext:String = "" 18 19 //選んだセルの特定と画面遷移 20 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 21 selectedtext = nikkinaiyou[indexPath.row] 22 performSegue(withIdentifier: "edit", sender: nil) 23 } 24 25 //画面遷移後に値渡しを行う 26 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 27 let watasi:AddViewController = (segue.destination as? AddViewController)! 28 watasi.watasitext = selectedtext! 29 } 30 31 //画面が開かれたときに行われるアクション 32 override func viewDidLoad() { 33 super.viewDidLoad() 34 // Do any additional setup after loading the view. 35 36 if UserDefaults.standard.object (forKey: "kagi") != nil{ nikkinaiyou = UserDefaults.standard.object (forKey: "kagi") as! [String]} 37 } 38} 39 40

追加編集画面の制御コードです

swift

1 2import UIKit 3var nikkinaiyou = [String]() 4class AddViewController: UIViewController { 5 6 7 @IBOutlet weak var nikkiText: UITextField! 8 9 //値を受け取る箱 10 var watasitext:String = "" 11 12 //追加ボタンを押したときのアクション 13 @IBAction func addbutton(_ sender: Any) { 14 nikkinaiyou.append(nikkiText.text!) 15 UserDefaults.standard.set(nikkinaiyou, forKey: "kagi") 16 } 17 18 //画面を開いたときに起こるアクション 19 override func viewDidLoad() { 20 super.viewDidLoad() 21 nikkiText.text = watasitext 22 23 } 24} 25

追加画像

イメージ説明

ご質問がありましたので追記します。

>矢印が多いのと、両画面ともmodalなのは意図してやってることですか?
遷移形式のことでしょうか。画像のようにshowで遷移させています。
イメージ説明
>参考にされてるページも...ですが、参考にされてるページとだいぶ違っているように見えますよ。
参考にしたページだけの情報では意図したものが作れなかったので試行錯誤しました。

>3つのメソッド内で変数の値を調べて、コンソールに表示される文字を教えて下さい。
すみません、おっしゃっている意味がよくわからないです。

>そのあと、"あああ"と打ったらうまくいくという方法で同じことを行って、結果を教えて下さい。
値が遷移画面に表示されないコード

swift

1 //画面遷移後に値渡しを行う 2 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 3 let watasi:AddViewController = (segue.destination as? AddViewController)! 4 watasi.watasitext = selectedtext 5 6 }

値が遷移画面に表示されるコード

swift

1 //画面遷移後に値渡しを行う 2 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 3 let watasi:AddViewController = (segue.destination as? AddViewController)! 4 watasi.watasitext = "あああ" 5 6 }

イメージ説明

入力したコードです

swift

1 2 3import UIKit 4 5class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource { 6 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 7 nikkinaiyou.count 8 } 9 10 //セルの再利用とリストに表示するアクション 11 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 12 let nikkicell = tableView.dequeueReusableCell(withIdentifier: "nikkicell", for: indexPath) 13 nikkicell.textLabel!.text = nikkinaiyou[indexPath.row] 14 return nikkicell 15 } 16 17 var selectedtext:String = "" 18 19 //選んだセルの特定と画面遷移 20 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 21 selectedtext = nikkinaiyou[indexPath.row] 22 print("didSelectRowAt/selectedtext: (selectedtext)") 23 performSegue(withIdentifier: "edit", sender: nil) 24 25 } 26 27 //画面遷移後に値渡しを行う 28 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 29 print("didSelectRowAt/selectedtext: (selectedtext)") 30 let watasi:AddViewController = (segue.destination as? AddViewController)! 31 watasi.watasitext = selectedtext 32 33 } 34 35 //画面が開かれたときに行われるアクション 36 override func viewDidLoad() { 37 super.viewDidLoad() 38 // Do any additional setup after loading the view. 39 40 if UserDefaults.standard.object (forKey: "kagi") != nil{ nikkinaiyou = UserDefaults.standard.object (forKey: "kagi") as! [String]} 41 print("didSelectRowAt/selectedtext: (selectedtext)") 42 } 43} 44

tretを選んだときに出力されたものです。
イメージ説明
イメージ説明

すみません、これでどうでしょうか。
イメージ説明

segueの詳細です。
イメージ説明
イメージ説明

追記です
イメージ説明
・unsegueを使って「戻る」仕様にしました
・条件分岐をつけて2画面に分けました

いろいろ試行錯誤してみましたが「作成」はできても「編集」というのは難しいように感じています。
アプローチを変えてrealmを使おうかと考えています。他にいい案ありましたら教えて下さい。

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

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

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

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

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

guest

回答2

0

ベストアンサー

エラーが出てる部分の、watasi.watasitext = selectedtext!の最後の!を削除して実行したらどうなりますか?


追記

矢印が多いのと、両画面ともmodalなのは意図してやってることですか?
参考にされてるページも...ですが、参考にされてるページとだいぶ違っているように見えますよ。

3つのメソッド内で変数の値を調べて、コンソールに表示される文字を教えて下さい。
そのあと、"あああ"と打ったらうまくいくという方法で同じことを行って、結果を教えて下さい。

swift

1   //選んだセルの特定と画面遷移 2 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 3 selectedtext = nikkinaiyou[indexPath.row] 4 print("didSelectRowAt/selectedtext: (selectedtext)"  // <= 追加して 5 performSegue(withIdentifier: "edit", sender: nil) 6 } 7 8 //画面遷移後に値渡しを行う 9 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 10 print("prepare/selectedtext: (selectedtext)" // <= 追加して 11 let watasi:AddViewController = (segue.destination as? AddViewController)! 12 watasi.watasitext = selectedtext! 13 } 14 15class AddViewController: UIViewController { 16 17 //画面を開いたときに起こるアクション 18 override func viewDidLoad() { 19 super.viewDidLoad() 20     print("AddViewController/watasitext: (watasitext)" // <= 追加して 21 nikkiText.text = watasitext 22 23 } 24}

追記

矢印1本でもできますが、どうしても2本でやりたいなら↓のようにしたら?
セグエの矢印には別々のidentifierを設定してください。
セルからVCに矢印を貼るとdidSelect内のコードが動く前に遷移します。

swift

1//選んだセルの特定と画面遷移 2func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 3 let str: = nikkinaiyou[indexPath.row] 4 // identifierが"edit"のセグエの矢印を実行する 5 performSegue(withIdentifier: "edit", sender: str) 6} 7 8//画面遷移後に値渡しを行う 9override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 10 if segue.identifier == "edit" { 11     // identifierが"edit"のセグエの矢印を実行する場合のみ値を遷移先にわたす。 12 let str: String? = sender as? String 13 let vc = segue.destination as? AddViewController 14 vc?. watasitext = str 15 } 16}

戻ってくる処理はいまのままだと無限ぐるぐるになってるので、unwindSegueで設定し直してください。
storyBoard上の戻ってくる矢印は不要です。

古いけどなんとかなるでしょ

また、遷移先で一つのボタンで編集と新規作成行う(戻る処理)ようですが、このままだとプログラムがどちらの処理なのかわからないので、そのへんを切り分ける処理も必要になります。

もう用意してあればいいですが。


追記

面倒なので、適当に作ったの置いときます。参考にでもしてみてください。

gitHub

これができないのに新しいものに手を出してなにかできるとは思えませんが…。

投稿2020/04/09 06:53

編集2020/04/10 02:26
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Daisuke0315

2020/04/09 07:10

お返事ありがとうございます。 なにも表示されません。 仮に watasi.watasitext = "ああ" などであれば正常に動作します。
退会済みユーザー

退会済みユーザー

2020/04/09 07:37

didSelectRowAtの中にprint(nikkinaiyou[indexPath.row])ってタイプして遷移させると、コンソールには何が表示されますか?
Daisuke0315

2020/04/09 07:57

画像を追加しましたが、選んだセルの内容がコンソールに出力されます
退会済みユーザー

退会済みユーザー

2020/04/09 08:11

遷移してないように見えるけど、なんで?
Daisuke0315

2020/04/09 08:55

誤解させてしまう画像ですみません。 この画像は遷移して戻ってきたところをスクショしたものです。
Daisuke0315

2020/04/09 11:33

ご質問に対して編集して回答しました。
退会済みユーザー

退会済みユーザー

2020/04/09 11:36

print(ホニャララ)を3ついれたので、該当箇所をコピペして、コンソールに出力された文字列を教えて下さい
Daisuke0315

2020/04/09 11:49

編集して回答しました。
退会済みユーザー

退会済みユーザー

2020/04/09 11:52

ラベルつけといたのに、全部同じのコピペしたらわかりませ〜ん
Daisuke0315

2020/04/09 12:08

すみません、理解できてなかったです。これでどうでしょうか。
退会済みユーザー

退会済みユーザー

2020/04/09 12:25

文字列を画像で貼るのはやめてください。 2本矢印が左から右につながってるでしょ、それを消してきちんとつなげ直してください。 各printを間違えなく貼ってくれているとしたらですが、 一本はセルから右のVCにつないであって、もう一本にはVCからVCにつないであるように感じます。 きちんとというのは、参考にした記事をよく読んでそのとおりにつなげてくださいという意味です。 それと戻ってくる矢印もそれじゃどうしようもないので、unwindSegueあたりでつなげてあげてください。 メソッドがちょっと変わったみたいだけど、あとで調べてリンクでも貼っときます
Daisuke0315

2020/04/09 12:41

左から右に出ている二本のsegueはセルを選んだときのものと新規作成するときのものです。 伝わりづらいかもしれませんので画像を貼っておきます。
退会済みユーザー

退会済みユーザー

2020/04/09 12:46

あー上の矢印は新規で使うのね、じゃあ、下を貼り直して、identifierをつけてあげて、 現状セルをタップすると、2つとも動いてるから、片方だけうごくようにしてください
Daisuke0315

2020/04/10 01:17

編集して回答しました。
Daisuke0315

2020/04/10 02:31

ありがとうございます、意図したものです。この方法では不可能だと思っていました。upして頂いたものを読み解いて改めてまとめなおしたいと思います。
guest

0

◇実現したいこと
tableviewを用いた日記アプリの作成

TableViewのセルをタップした時に、別画面に遷移させたい。(←できました)
遷移させる際にセルの情報を取得したい。(←できました)
編集した情報を上書きする(←できました)

教えていただいたことを参考にして試行錯誤して実現することができました。
感謝の報告と備忘録を兼ねてまとめていきたいと思います。

動きはしますが動き方もおかしいところがありますので、指摘いただけると嬉しいです。

◇難しかったところ

・テーブル作成方法について
1.何行のテーブルか決める
2.セルに何が書かれるか決める

・ストーリーボードを利用しない画面遷移の方法について
1.ストーリーボードにidをつける
2.どの画面に遷移するか紐付ける
3.どのように遷移するか決める

・テーブルセルを用いた画面遷移について
1.どのセルを押されたらアクションをするか決める

一人で考えていたら全然できませんでした。質問に答えていただき感謝しています。

イメージ説明

ViewController

swift

1 2 3 4import UIKit 5 6class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource { 7 var 日記を入れる箱:[String] = ["テスト","aaa"] 8 9 var インデックスパスを返してもらう箱 = 0 10 var どこから来たかを受け取る箱 = "" 11 @IBAction func unwindToTop(segue: UIStoryboardSegue) { 12 } 13 14 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 15 return 日記を入れる箱.count 16 } 17 @IBOutlet weak var リストテーブル: UITableView! 18 19 func tableView(_ リストテーブル: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 20 let セル = リストテーブル.dequeueReusableCell(withIdentifier: "セル", for: indexPath) 21 22 セル.textLabel?.text = 日記を入れる箱[indexPath.row] 23 return セル 24 } 25 func tableView(_ リストテーブル: UITableView, didSelectRowAt indexPath: IndexPath) { 26 let リストから編集へ = self.storyboard?.instantiateViewController(identifier: "HenshuuViewController") as! HenshuuViewController 27 リストから編集へ.編集したい内容を受け取る箱 = 日記を入れる箱[indexPath.row] 28 リストから編集へ.インデックスパスを受け取る箱 = indexPath.row 29 self.present(リストから編集へ, animated: true, completion: nil) 30 } 31 32 @IBAction func 新規移動ボタン(_ sender: Any) { 33 let リストから新規作成へ = self.storyboard?.instantiateViewController(identifier: "SinkiViewController") as! SinkiViewController 34 self.present(リストから新規作成へ, animated: true, completion: nil) 35 } 36 37 override func viewDidLoad() { 38 super.viewDidLoad() 39 日記を入れる箱 = UserDefaults.standard.array(forKey: "鍵") as! [String] 40 41 42 } 43 override func viewWillAppear(_ animated: Bool) { 44 super.viewWillAppear(animated) 45 46 47 } 48 49} 50 51 52

HenshuuViewController

swift

1 2 3 4import UIKit 5 6class HenshuuViewController: UIViewController { 7 @IBOutlet weak var 編集する内容: UITextView! 8 var 編集したい内容を受け取る箱:String = "" 9 var 日記を入れる箱 = UserDefaults.standard.array(forKey: "鍵") as! [String] 10 11 var インデックスパスを受け取る箱:Int = 0 12 override func viewDidLoad() { 13 14 super.viewDidLoad() 15 編集する内容.text = 編集したい内容を受け取る箱 16 17 // Do any additional setup after loading the view. 18 } 19 20 @IBAction func 編集ボタン(_ sender: Any) { 21 let 編集からリストへ = self.storyboard?.instantiateViewController(identifier: "ViewController") as! ViewController 22 日記を入れる箱[インデックスパスを受け取る箱] = 編集する内容.text 23 UserDefaults.standard.set(日記を入れる箱, forKey: "鍵") 24 self.present(編集からリストへ, animated: true, completion: nil) 25 } 26 27 /* 28 // MARK: - Navigation 29 30 // In a storyboard-based application, you will often want to do a little preparation before navigation 31 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 32 // Get the new view controller using segue.destination. 33 // Pass the selected object to the new view controller. 34 } 35 */ 36 37} 38

SinkiViewController

swift

1 2import UIKit 3 4class SinkiViewController: UIViewController { 5 6 7 @IBOutlet weak var 日記の内容: UITextView! 8 9 @IBOutlet weak var 日付: UILabel! 10 11 let date = Date() 12 13 let df = DateFormatter() 14 var 日記を入れる箱:[String] = [] 15 16 17 18 override func viewDidLoad() { 19 super.viewDidLoad() 20 df.dateFormat = "yyyy-MM-dd HH:mm:ss" 21 日付.text = df.string(from: date) 22 日記を入れる箱 = UserDefaults.standard.array(forKey: "鍵") as! [String] 23 24 25 } 26 27 @IBAction func 保存(_ sender: Any) { 28 let 新規からリストへ = self.storyboard?.instantiateViewController(identifier: "ViewController") as! ViewController 29 日記を入れる箱.insert(日記の内容.text, at: 0) 30 UserDefaults.standard.set(日記を入れる箱, forKey: "鍵") 31 print("追加画面(日記を入れる箱)") 32 self.present(新規からリストへ, animated: true, completion: nil) 33 34 } 35 36 /* 37 // MARK: - Navigation 38 39 // In a storyboard-based application, you will often want to do a little preparation before navigation 40 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 41 // Get the new view controller using segue.destination. 42 // Pass the selected object to the new view controller. 43 } 44 */ 45 46} 47 48

投稿2020/04/13 04:53

Daisuke0315

総合スコア23

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

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

退会済みユーザー

退会済みユーザー

2020/04/13 12:39

presentで戻らないでね。それ戻ってないからね。 https://qiita.com/akatsuki174/items/45d4bd7cb150defbf116 それと、皆さんがどうだか知りませんが、私は、コメント部分以外に日本語が書いてあるコードは読めないようです。
Daisuke0315

2020/04/13 12:48

すみません、英語苦手で。。また質問することあると思いますが今後ともよろしくおねがいします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問