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

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

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

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

Swift

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

Q&A

解決済

1回答

781閲覧

PrepareforSegueを利用してDouble型の数値配列データを別画面に渡す方法を教えてください。

YUSAA

総合スコア11

Xcode

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

Swift

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

0グッド

0クリップ

投稿2021/02/16 05:38

前提・実現したいこと

健康管理アプリを作っています。
writeViewControllerで保存したDouble型の数値配列データを、ViewControllerを介して、healthViewControllerに渡したいです。prepareforSegueを利用して、遷移時に数値を渡そうとしているのですが、「Thread 1: signal SIGABRT」となり、prepareforSegueのコードで止められてしまいます。どのようにして値を渡すのが良いのでしょうか?具体的に教えていただけると嬉しいです。

該当のソースコード(ViewController)

Swift

1class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 2 3 var healthNumber1 = [Double]() 4 5 var heinetuDate = [Double]() 6 7 var todayDate = [String]() 8 9 @IBOutlet weak var dateTableView : UITableView! 10 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 14 let nib = UINib(nibName: "dateTableViewCell", bundle: nil) 15 dateTableView.register(nib, forCellReuseIdentifier: "dateTableViewCell") 16 17 // yyyy年MM月01日 12時 18 let lastDate = DateComponents(calendar: Calendar.current, day: 1, hour: 12).date! 19 20 // yyyy年MM月15日 11時 21 let now = DateComponents(calendar: Calendar.current, day: 15, hour: 11).date! 22 23 let lastDateStartOfDay = Calendar.current.startOfDay(for: lastDate) 24 let nowStartOfDay = Calendar.current.startOfDay(for: now) 25 26 let elapsedDays = Calendar.current.dateComponents([.day], from: lastDateStartOfDay, to: nowStartOfDay).day! 27 28 if elapsedDays > 14 { 29 30 todayDate.removeAll() 31 healthNumber1.removeAll() 32 33 UserDefaults.standard.set(healthNumber1, forKey: "HealthNumber1") 34 UserDefaults.standard.set(todayDate, forKey: "TodayDate") 35 } 36 37 } 38 39 override func viewDidAppear(_ animated: Bool) { 40 self.dateTableView.reloadData() 41 } 42 43 override func viewWillAppear(_ animated: Bool) { 44 super.viewWillAppear(animated) 45 46 if UserDefaults.standard.object(forKey: "HealthNumber1") != nil { 47 healthNumber1 = UserDefaults.standard.object(forKey: "HealthNumber1") as! [Double] 48 } 49 50 if UserDefaults.standard.object(forKey: "HeinetuDate") != nil { 51 heinetuDate = UserDefaults.standard.object(forKey: "HeinetuDate") as! [Double] 52 } 53 54 if UserDefaults.standard.object(forKey: "TodayDate") != nil { 55 todayDate = UserDefaults.standard.object(forKey: "TodayDate") as! [String] 56 } 57 58 } 59 60 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 61 if segue.identifier == "goThird" { 62 63 let thirdVc = segue.destination as! healthViewController 64 // 値を渡す 65 thirdVc.numberRow = Double((sender as! IndexPath).row) 66 67 } 68 69 } 70 71 72 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 73 74 return todayDate.count 75 } 76 77 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 78 79 let dateCell = tableView.dequeueReusableCell(withIdentifier: "dateTableViewCell") as! dateTableViewCell 80 81 dateCell.date2Label.text = todayDate[indexPath.row] 82 83 if UserDefaults.standard.object(forKey: "HealthNumber1") != nil { 84 let bodyNum = UserDefaults.standard.object(forKey: "HealthNumber1") as! [Double] 85 86 let strf: [String] = bodyNum.map{NSString(format: "%.1f", $0) as String} 87 88 dateCell.health2Label.text = strf[indexPath.row] 89 90 } 91 92 93 94 95 return dateCell 96 } 97 98

該当のソースコード(writeViewController)

Swift

1class writeViewController: UIViewController,UIPickerViewDelegate,UIPickerViewDataSource { 2 3 var healthNumber1 = [Double]() 4 5 var todayDate = [String]() 6 7 @IBOutlet weak var outputLabel1 : UILabel! 8 @IBOutlet weak var decideButton : UIButton! 9 @IBOutlet weak var healthPickerView: UIPickerView! 10 @IBOutlet weak var smellSwitch : UISwitch! 11 @IBOutlet weak var tasteSwitch : UISwitch! 12 @IBOutlet weak var dateLabel : UILabel! 13 14 var smellNumber :Int = 0 15 var tasteNumber :Int = 0 16 17// var outputdate : Double = 0.0 18 19 let list1 : [Double] = [35.0,35.1,35.2,35.3,35.4,35.5,35.6,35.7,35.8,35.9,36.0,36.1,36.2,36.3,36.4,36.5,36.6,36.7,36.8,36.9,37.0,37.1,37.2,37.3,37.4,37.5,37.6,37.7,37.8,37.9,38.0,38.1,38.2,38.3,38.4,38.5,38.6,38.7,38.8,38.9,39.0,40.0,40.1,40.2,40.3,40.4,40.5,40.6,40.7,40.8,40.9,41.0] 20 21 22 override func viewDidLoad() { 23 super.viewDidLoad() 24 25 if UserDefaults.standard.object(forKey: "HealthNumber1") != nil { 26 healthNumber1 = UserDefaults.standard.object(forKey: "HealthNumber1") as! [Double] 27 } 28 29 if UserDefaults.standard.object(forKey: "TodayDate") != nil { 30 todayDate = UserDefaults.standard.object(forKey: "TodayDate") as! [String] 31 } 32 33 if #available(iOS 13.0, *) { 34 self.overrideUserInterfaceStyle = .light 35 } else { 36 // Fallback on earlier versions 37 } 38 39 //DateFormatterクラスのインスタンス生成 40 let dateFormatter = DateFormatter() 41 //ロケールの設定(日本・東京) 42 dateFormatter.locale = Locale(identifier: "ja_JP") 43 //スタイルの設定 44 dateFormatter.dateStyle = .medium 45 46 let now = Date() 47 dateLabel.text = "(dateFormatter.string(from: now))" 48 49 50 } 51 52 //PickerViewの設定 53 func numberOfComponents(in pickerView: UIPickerView) -> Int { 54 55 return 1 56 } 57 58 func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 59 60 return list1.count 61 62 } 63 64 // ドラムロールの各タイトル 65 func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 66 67 return String(format: "%.1f", list1[row]) 68 } 69 70 71 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 72 73 let output = list1[pickerView.selectedRow(inComponent: 0)] 74 75 outputLabel1.text = "(output)" 76 } 77 78 //ボタンの設定 79 @IBAction func TodoAddButten(_ sender: Any) { 80 81 let isOn = smellSwitch.isOn 82 if isOn == true { 83 smellNumber = 1 84 } 85 86 let isOn2 = tasteSwitch.isOn 87 if isOn2 == true { 88 tasteNumber = 1 89 } 90 91 healthNumber1.append(Double(outputLabel1.text!) ?? -1) 92 93 todayDate.append(dateLabel.text!) 94 95 // 追加ボタンを押したらテキストフィールドを空にする 96 outputLabel1.text = "" 97 98 UserDefaults.standard.set(healthNumber1, forKey: "HealthNumber1") 99 100 UserDefaults.standard.set(todayDate, forKey: "TodayDate") 101 102 UserDefaults.standard.set(smellNumber, forKey: "SmellNumber") 103 104 UserDefaults.standard.set(tasteNumber, forKey: "TasteNumber") 105 106 self.navigationController?.popToRootViewController(animated: true) 107 } 108

該当のソースコード(healthViewController)

Swift

1class healthViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 2 3 @IBOutlet weak var healthTableView : UITableView! 4 5 var healthNumber1 = [Double]() 6 7 var heinetuDate = [Double]() 8 9 var numberRow : Double = 0.0 10 11 var heinetuRow : Double = 0.0 12 13 var healthNum : Double = 0.0 14 15 var heinetuNum : Double = 0.0 16 17 18 override func viewDidLoad() { 19 super.viewDidLoad() 20 21 22 if UserDefaults.standard.object(forKey: "HealthNumber1") != nil { 23 let numbers = UserDefaults.standard.object(forKey: "HealthNumber1") as! [Double] 24 25 healthNum = numbers[Int((Double(numberRow)))] 26 27 } 28 29 if UserDefaults.standard.object(forKey: "HeinetuDate") != nil { 30 let heinetuNumber = UserDefaults.standard.object(forKey: "HeinetuDate") as! [Double] 31 32 heinetuNum = heinetuNumber[Int(Double(heinetuRow))] 33 } 34 35

補足情報(FW/ツールのバージョンなど)

Xcodeバージョン12.4

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

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

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

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

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

guest

回答1

0

ベストアンサー

Swift

1 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 2 if segue.identifier == "goThird" { 3 // ** 落ちる可能性(1) ** 4 let thirdVc = segue.destination as! healthViewController 5 // ** 落ちる可能性(2) ** 6 thirdVc.numberRow = Double((sender as! IndexPath).row) 7 } 8 }

// ** 落ちる可能性(1) ** の次の行で落ちているのであれば、落ちる理由は強制キャスト失敗による実行時エラーですので、 "goThird" と名前をつけた Segue の遷移先のカスタムクラスが healthViewController では無い可能性が高いと思います。

// ** 落ちる可能性(2) ** の次の行であれば、senderIndexPath として強制キャストに失敗している原因が高いと思います。

そもそも、performSegue(withIdentifier:) と組み合わせずに prepare(for:UIStoryboardSegue:) を使っているのであれば、Segue は Action Segue だと判断しています。そうであれば、sender に入る値は IndexPath ではなく、タップされた UI部品のインスタンスですので、そこに注意していただく必要があります。

Notifies the view controller that a segue is about to be performed.

の Discussion の節を見ていただくとわかりますが、

Discussion
// 中略
Because segues can be triggered from multiple sources, you can use the information in the segue and sender parameters to disambiguate between different logical paths in your app. For example, if the segue originated from a table view, the sender parameter would identify the table view cell that the user tapped. You could then use that information to set the data on the destination view controller.

とあります。

For example, if the segue originated from a table view, the sender parameter would identify the table view cell that the user tapped. You could then use that information to set the data on the destination view controller.

のところに記述してありますが、「たとえば、table view から張られた segue の場合、senderパラメータから tavle view のどのセルをタップしたのか判断することができます」という意味合いの文章が書かれています。

ここからは明確には読み取れませんが、上記の事例の場合、実際には sender に入るのは UITableViewCell のインスタンスであって、IndexPath のインスタンスではない、という点に注意が必要です。

投稿2021/02/16 10:50

TsukubaDepot

総合スコア5086

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

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

YUSAA

2021/02/16 11:13

丁寧な回答ありがとうございます。では、Double型の数値をwriteViewControllerからhealthViewControllerに渡すのは、prepareforsegueを利用せずに、UserDefaultsで渡せばよろしいのでしょうか?その場合、どうすれば良いのでしょうか?
TsukubaDepot

2021/02/16 11:25

以前にどこかの講座で習っていた、という話がありましたが、その時は Segue の使い方は習わなかったのでしょうか。
TsukubaDepot

2021/02/16 11:26

あと、ご質問本文には > writeViewControllerで保存したDouble型の数値配列データを、ViewControllerを介して、healthViewControllerに渡したいです。 と買いてありますが、2021/02/16 20:13 のコメントでは > writeViewControllerからhealthViewControllerに渡すのは、 と経由する View Controller が異なっています。 どちらが正しいのでしょうか。
YUSAA

2021/02/28 06:34 編集

返信遅れて大変申し訳ございません。Segueを使い方は習いました。ViewControllerからhealthViewControllerに値を渡すというのが正しいです。
TsukubaDepot

2021/02/28 13:17

この前も同じことを伺ったような気がしますが、Segueには2種類ありますが、その違いはご存知でしょうか 一つは View Controller から遷移先の View Controller に Segue を引っ張る「Manual Segue」と、ボタンや TableView などの UI 部品から遷移先に Segue を引っ張る「Action Segue」の2つがあります。 このどちらを使っているのか、YUSAA さんにきちんとご説明いただかないと、この問題は解決できないと思います。 2つの Segue の違いは下記の URL が詳しいです。 https://capibara1969.com/229/ ちなみに、コードから推測すると、performSegue がないため、おそらく Action Segue だと思います。 その場合、prepare(for:sender:) の sender には indexPath ではなく、UITableViewCell のインスタンスが入ります。 そうなると、上記の回答の説明の通りになりますので、それをよく読んでいただき、何を間違っているのかよく把握されるのがいいかと思います。 Action Segue を使った場合、indexPath を直接取得することはできません。 ただし、sender にはタップを受けとったセルのインスタンスが渡されるので、相応のメソッドを使い、そこから indexPath を取得することは一応可能です(非推奨な方法ですが)。 ただ、この目的であれば、本来は Manual Segue を使い、UITableView の didSelectAtRow あたりのメソッドで performSegue と組み合わせるのが常套手段だと思います。
YUSAA

2021/02/28 13:43

講座で習った時は、Cellをタップした時に呼び出されるようにしていたためActionSegueを利用していました。ManualSegueで試してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問