72389


トレーニング内容を保存し、カレンダーの下に表示したいと思います。  
EventViewControllerのdidTapAddNoteButtonを押してViewControllerへ画面遷移し、  
遷移元のmenuLabelを遷移先のvcMenuLabelへ表示したいのですが、遷移先のUITableViewには何も表示されません。  
遷移先のセル内でnoteTableView.reloadData()と入れてみましたが、  
そもそも記述の仕方が違うのでしょうか？  
MacOS11.0.1 Xcode12.2

EventViewController.swift

[code]

    import UIKit
    
    class EventViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
        
        @IBOutlet weak var partsPickerView: UIPickerView!
        @IBOutlet weak var partsLabel: UILabel!
        @IBOutlet weak var menuPickerView: UIPickerView!
        @IBOutlet weak var menuLabel: UILabel!
        @IBOutlet weak var menuTextField: UITextField!
        @IBOutlet weak var kgTextField1: UITextField!
        @IBOutlet weak var kgTextField2: UITextField!
        @IBOutlet weak var repTextField1: UITextField!
        @IBOutlet weak var repTextField2: UITextField!
        
        var menuDataList: [String: [String]] = [
            "脚": ["スクワット","レッグプレス","レッグエクステンション","レッグカール"],
            "背中": ["デッドリフト","ベントオーバーローイング","チンニング","ラットプルダウン"],
            "胸": ["バーベルベンチプレス","ダンベルベンチプレス","インクラインダンベルベンチプレス","ペックフライ"]
        ]
        var partsDataList: [String] = [
            "脚","背中","胸"
        ]
        var selectedParts = ""
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            partsPickerView.delegate = self
            partsPickerView.dataSource = self
            menuPickerView.delegate = self
            menuPickerView.dataSource = self
            menuTextField.delegate = self
            kgTextField1.delegate = self
            kgTextField2.delegate = self
            repTextField1.delegate = self
            repTextField2.delegate = self
    
            partsPickerView.tag = 1
            menuPickerView.tag = 2
            selectedParts = partsDataList[0]
            
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
            
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
            
            menuTextField.keyboardType = UIKeyboardType.default
            kgTextField1.keyboardType = UIKeyboardType.decimalPad
            kgTextField2.keyboardType = UIKeyboardType.decimalPad
            repTextField1.keyboardType = UIKeyboardType.decimalPad
            repTextField2.keyboardType = UIKeyboardType.decimalPad
            
            menuDataList = userDefaults.dictionary(forKey: "keyMenuDataList") as? [String: [String]] ?? [:]
        }
    
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return 1
        }
        
        func pickerView(_ pickerView: UIPickerView,
                        numberOfRowsInComponent component: Int) -> Int {
            if pickerView.tag == 1{
                return partsDataList.count
            } else if pickerView.tag == 2{
                return menuDataList[selectedParts]?.count ?? 0
            } else {
                return 0
            }
        }
        
        func pickerView(_ picker: UIPickerView,
                        titleForRow row: Int,
                        forComponent component: Int) -> String? {
            if picker.tag == 1 {
                return partsDataList[row]
            } else if picker.tag == 2 {
                return menuDataList[selectedParts]?[row] ?? ""
            } else {
                return ""
            }
        }
        
        func pickerView(_ pickerView: UIPickerView,
                        didSelectRow row: Int,
                        inComponent component: Int) {
            if pickerView.tag == 1 {
                partsLabel.text = partsDataList[row]
                selectedParts = partsDataList[row]
                menuPickerView.reloadAllComponents()
            } else if pickerView.tag == 2 {
                menuLabel.text = menuDataList[selectedParts]?[row] ?? ""
            } else {
                return
            }
        }
        
        @IBAction func tapScreen(_ sender: Any) {
            self.view.endEditing(true)
        }
        
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            return true
        }
        
        @objc func keyboardWillShow(notification: NSNotification) {
            if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
                if self.view.frame.origin.y == 0 {
                    self.view.frame.origin.y -= keyboardSize.height
                } else {
                    let suggestionHeight = self.view.frame.origin.y + keyboardSize.height
                    self.view.frame.origin.y -= suggestionHeight
                }
            }
        }
        
        @objc func keyboardWillHide() {
            if self.view.frame.origin.y != 0 {
                self.view.frame.origin.y = 0
            }
        }
        
        let userDefaults = UserDefaults.standard
        let keyMenuDataList = "newMenu"
        
        //種目を追加ボタン
        @IBAction func didTapAddMenuButton(_ sender: Any) {
            if (menuTextField.text?.isEmpty ?? true == false) {
                let okAlert = UIAlertController(title: "保存されました。", message: "", preferredStyle: .alert)
                let closeAction = UIAlertAction(title: "閉じる", style: .default) { (action: UIAlertAction) in }
                okAlert.addAction(closeAction)
                present(okAlert, animated: true, completion: nil)
                if let text = menuTextField.text {
                    menuDataList[selectedParts]?.append(text)
                    userDefaults.set(menuDataList, forKey: "keyMenuDataList")
                }
            } else {
                let ngAlert = UIAlertController(title: "テキストが空です。", message: "", preferredStyle: .alert)
                let closeAction = UIAlertAction(title: "閉じる", style: .default) { (action: UIAlertAction) in }
                ngAlert.addAction(closeAction)
                present(ngAlert, animated: true, completion: nil)
            }
            menuPickerView.reloadAllComponents()
        }
        
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            
            if segue.identifier == "toSegueViewController" {
                //遷移先のViewControllerを取得
                let toVC = segue.destination as? ViewController
                //用意した遷移先の変数に値を渡す
                toVC?.vcMenuValue = self.menuLabel.text
                
            }
        }
        
        //ノートを追加するボタン ボタンを押したらViewControllerに画面遷移して各labelの値を渡す
        @IBAction func didTapAddNoteButton(_ sender: Any) {
            //画面遷移
            self.performSegue(withIdentifier: "toSegueViewController", sender: nil)
            
        }
        
    }
    
[/code]

ViewController.swift

[code]

    import UIKit
    import FSCalendar
    import CalculateCalendarLogic
    import RealmSwift
    
    class NoteTableViewCell: UITableViewCell {
        @IBOutlet weak var vcMenuLabel: UILabel!
    }
    
    class ViewController: UIViewController, FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance, UITableViewDataSource, UITableViewDelegate {
        
        @IBOutlet weak var calendar: FSCalendar!
        @IBOutlet weak var noteTableView: UITableView!
        
        //遷移先に渡したい値を格納する変数
        var vcMenuValue : String?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.navigationController!.navigationBar.tintColor = .black
            self.calendar.dataSource = self
            self.calendar.delegate = self
            self.navigationItem.hidesBackButton = true
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        
        fileprivate let gregorian: Calendar = Calendar(identifier: .gregorian)
        fileprivate lazy var dateFormatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd"
            return formatter
        }()
        
        func judgeHoliday(_ date : Date) -> Bool {
            let tmpCalendar = Calendar(identifier: .gregorian)
            
            let year = tmpCalendar.component(.year, from: date)
            let month = tmpCalendar.component(.month, from: date)
            let day = tmpCalendar.component(.day, from: date)
            
            let holiday = CalculateCalendarLogic()
            
            return holiday.judgeJapaneseHoliday(year: year, month: month, day: day)
        }
        
        func getDay(_ date:Date) -> (Int,Int,Int){
            let tmpCalendar = Calendar(identifier: .gregorian)
            let year = tmpCalendar.component(.year, from: date)
            let month = tmpCalendar.component(.month, from: date)
            let day = tmpCalendar.component(.day, from: date)
            return (year,month,day)
        }
        
        func getWeekIdx(_ date: Date) -> Int{
            let tmpCalendar = Calendar(identifier: .gregorian)
            return tmpCalendar.component(.weekday, from: date)
        }
        
        func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
            if self.judgeHoliday(date){
                return UIColor(red: 0.9, green: 0.3, blue: 0.3, alpha: 1.0)
            }
            
            let weekday = self.getWeekIdx(date)
            if weekday == 1 {
                return UIColor(red: 0.9, green: 0.3, blue: 0.3, alpha: 1.0)
            }
            else if weekday == 7 {
                return UIColor(red: 0.1, green: 0.3, blue: 0.8, alpha: 1.0)
            }
            
            return nil
        }
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1
        }
        
        //セルの内容
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! NoteTableViewCell
            cell.vcMenuLabel.text = vcMenuValue
            
            return cell
            
        }
    }
    
[/code]


CC BY-SA 4.0
2020-12-04T01:27:06.357
72385
2020-12-04T09:40:54.323
2020-12-04T09:40:54.323
18540
42090
question
swift ios xcode
IBActionで画面遷移しUITableViewのUILabelへ値を渡して表示したい。


> そもそも記述の仕方が違うのでしょうか？

どの部分の「記述の仕方」が念頭にあるのかわかりませんが、「違う」ところが複数あるようです。

* * *

# 絶対にやってはいけない

`tableView(_:cellForRowAt:)`の中で`noteTableView.reloadData()`を呼んでいますが、これはiOSでは「絶対にやってはいけない」ことの一つです。

iOSは`reloadData()`が呼ばれると、必要に応じて`tableView(_:numberOfRowsInSection:)`や`tableView(_:cellForRowAt:)`を呼び出します。したがって、`tableView(_:cellForRowAt:)`の中で`reloadData()`を呼ぶと無限再起が起こり(運が良ければ)アプリがクラッシュします。

運が悪いと「クラッシュもエラー表示もなく動いているように見えるのに、全く期待通りの動作にならない」こともありえます。

一体どんな時に`reloadData()`を呼ばないといけないのかを十分理解して使いましょう。

* * *

## やっても意味のないことをやっている

### `ViewController.viewDidLoad()`の中のこの行:

[code]

            vcMenuLabel?.text = vcMenuValue
    
[/code]

「vcMenuLabelは省略も設定もしておりません」と言うことですから、`vcMenuLabel`は常にnilです。したがって、Optional
Chainingを使っているこの行は黙って無視され、何の動作もしません。

### `ViewController.tableView(_:cellForRowAt:)`の中のこの行:

[code]

            let vcMenuLabel = UILabel(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 30))
    
[/code]

この行であなたは`UILabel`のインスタンスを作成していますが、せっかく作成したインスタンスをどこにも設定しないまま捨ててしまっています。(Xcodeがこの行に警告を出しているはずです。)

コメントに簡単に書きましたが、この行では先頭に`let
`が付いているため、ローカル変数の宣言となり、インスタンス変数の`vcMenuLabel`とは同じ名前ですが、中身は全くの別物です。

また、なんとなくで宣言された`UILabel`があなたの心の中を読んでセルの中に表示される、なんてことは決して起こりません。

* * *

# どこをどう直すか

「tableViewの各セルに表示したい」と言うことなのでしたら、まずは「各セル」に表示用のラベルを定義してやらないといけません。

(以下は、標準セルの`textLabel`を使うなら不要なのですが、カスタムのPrototype
Cellを使うならラベル1個で済むことはないはずなので、説明しておきます。)

コードを見る限りPrototype
Cellsを利用しているようなので、storyboard上でLabel(`UILabel`)をセル上の適切な位置に置いてください。

[![セルの追加](https://i.stack.imgur.com/MgdZM.png)](https://i.stack.imgur.com/MgdZM.png)

次にViewController.swift にカスタムセルクラスを定義します。

[code]

    import UIKit
    
    class NoteTableViewCell: UITableViewCell {
        @IBOutlet var vcMenuLabel: UILabel!
    }
    
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        //...
    }
    
[/code]

そうしたら、使用するPrototype Cellの **Custom Class** を`NoteTableViewCell`にします。

[![Custom
Class設定](https://i.stack.imgur.com/5VbZm.png)](https://i.stack.imgur.com/5VbZm.png)

これでAssistant Editorが正しく開くようになるはず(*)なので、storyboard上のLabelを`@IBOutlet var
vcMenuLabel: UILabel!`に接続してください。

(*) うちのXcode(12.2)は、一度再起動してやらないとダメでした。

ここまでで **`UILabel`をセルに表示する準備は完了**
です。ラベル一つを追加するだけなら、コードで書いた方が楽なのですが、今後のことを考えるとstoryboard上でセルの編集もできるようにしておいた方がいいでしょう。

後は`ViewController`クラスを次のような感じに書き換えれば動くはずです。

[code]

    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        
        @IBOutlet weak var noteTableView: UITableView!
        //↓使わない
        //var vcMenuLabel: UILabel!
        
        //遷移先に渡したい値を格納する変数
        var vcMenuValue : String?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            //戻るボタンを非表示
            self.navigationItem.hidesBackButton = true
            
            //↓`viewDidLoad()`では受け渡しデータの処理は行わない
            //(何か処理が必要なら`viewWillAppear(_:)`の方が良い)
            //vcMenuLabel?.text = vcMenuValue
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
        //...
    
        //セルの行数
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1
        }
        
        //セルの内容
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            //`as!`を意図的に使っている。ここでクラッシュする場合、ここまでの設定のどこかに誤りがある。
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! NoteTableViewCell
            //使われていない変数ではなく、セルの`vcMenuLabel`を設定する
            cell.vcMenuLabel.text = vcMenuValue
            //↓ダメ、絶対
            //noteTableView.reloadData()
            //...
            return cell
        }
        
        //...
    }
    
[/code]

* * *

ご質問の文面に表れていない情報によっては、若干の修正が必要になるかもしれませんが、とりあえずは試していただいて、うまくいかなければより詳細な情報をお示しいただいた上でコメントしてください。


CC BY-SA 4.0
2020-12-04T05:19:14.780
72389
2020-12-04T05:19:14.780
13972
72385
answer