2

I'm having a crash when unwinding from RouteTableViewControllerto AlarmAddEditViewController. in console I see the message : *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<fix_it_mapView.RouteTableViewController: 0x7ffad352e4a0>) has no segue with identifier 'routeUnwindSegue''.

It is actually declared as the other tableVC in here:

import Foundation

struct Id {
    static let stopIdentifier = "Alarm-ios-swift-stop"
    static let snoozeIdentifier = "Alarm-ios-swift-snooze"

    static let addSegueIdentifier = "addSegue"

    static let editSegueIdentifier = "editSegue"

    static let saveSegueIdentifier = "saveEditSegue"

    static let soundSegueIdentifier = "soundSegue"

    static let labelSegueIdentifier = "labelEditSegue"

    static let weekdaysSegueIdentifier = "weekdaysSegue"

    static let settingIdentifier = "setting"

    static let musicIdentifier = "musicIdentifier"

    static let alarmCellIdentifier = "alarmCell"

    static let routeSegueIdentifier = "routeSegue"

    static let routeIdentifier = "routeIdentifier"


    static let labelUnwindIdentifier = "labelUnwindSegue"
    static let soundUnwindIdentifier = "soundUnwindSegue"
    static let weekdaysUnwindIdentifier = "weekdaysUnwindSegue"


    static let routeUnwindIdentifier = "routeUnwindSegue"

} 

This is the RouteTableViewController:

import UIKit

class RouteTableViewController: UITableViewController {

    var numberOfRoutes = NewMapViewController.userRoutesNameArray.count

    var routeLabel: String!
    var routeId: String!
    var dataPassed: String?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.dataSource = self
        self.tableView.delegate = self

    }

//    override func viewWillDisappear(_ animated: Bool) {
//        performSegue(withIdentifier: Id.routeUnwindIdentifier, sender: self)
//    }


    override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        guard let header = view as? UITableViewHeaderFooterView else { return }
        header.textLabel?.textColor =  UIColor.gray
        header.textLabel?.font = UIFont.boldSystemFont(ofSize: 10)
        header.textLabel?.frame = header.frame
        header.textLabel?.textAlignment = .left
    }


    // MARK: - Table view data source

    //DECIDE HOW MANY SECTIONS
    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    //DECIDE HOW MANY ROWS ARE IN EACH SECTION
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
            return NewMapViewController.userRoutesNameArray.count
    }

    //SET THE TITLE FOR EACH SECTION BASED ON ARRAY ELEMENTS

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "ROTTE DISPONIBILI"
    }

    //SET HEIGHT FOR HEADER IN SECTION
    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 40.0
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell = tableView.dequeueReusableCell(withIdentifier: Id.routeIdentifier)
        if(cell == nil) {
            cell = UITableViewCell(
                style: UITableViewCellStyle.default, reuseIdentifier: Id.routeIdentifier)
        }
        cell!.textLabel!.text = NewMapViewController.userRoutesNameArray[indexPath.item]

            if cell!.textLabel!.text == routeLabel {
                cell!.accessoryType = UITableViewCellAccessoryType.checkmark
            }

        return cell!
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath)
//        cell?.accessoryType = UITableViewCellAccessoryType.checkmark
        routeLabel = cell?.textLabel?.text!
        cell?.setSelected(true, animated: true)
        cell?.setSelected(false, animated: true)

        let cells = tableView.visibleCells
        for c in cells {
            let section = tableView.indexPath(for: c)?.section
            if (section == indexPath.section && c != cell) {
                c.accessoryType = UITableViewCellAccessoryType.none
            }
        }
        routeLabel = cell!.textLabel!.text
                performSegue(withIdentifier: Id.routeUnwindIdentifier, sender: self) // crash
//
//        self.dismiss(animated: true, completion: nil)  // doesnt gee selected to receiver vc
    }


}

And this is the ÀlarmAddEditViewController`:

import UIKit
import Foundation
import MediaPlayer

class AlarmAddEditViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{

    @IBOutlet weak var datePicker: UIDatePicker!
    @IBOutlet weak var tableView: UITableView!

    var alarmScheduler: AlarmSchedulerDelegate = Scheduler()
    var alarmModel: Alarms = Alarms()
    var segueInfo: SegueInfo!
    var snoozeEnabled: Bool = false
    var enabled: Bool!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        alarmModel=Alarms()
        tableView.reloadData()
        snoozeEnabled = segueInfo.snoozeEnabled
        super.viewWillAppear(animated)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func saveEditAlarm(_ sender: AnyObject) {
        let date = Scheduler.correctSecondComponent(date: datePicker.date)
        let index = segueInfo.curCellIndex
        var tempAlarm = Alarm()
        tempAlarm.date = date
        tempAlarm.label = segueInfo.label
        tempAlarm.enabled = true
        tempAlarm.routeLabel = segueInfo.routeLabel
        tempAlarm.mediaLabel = segueInfo.mediaLabel
        tempAlarm.mediaID = segueInfo.mediaID
        tempAlarm.snoozeEnabled = snoozeEnabled
        tempAlarm.repeatWeekdays = segueInfo.repeatWeekdays
        tempAlarm.uuid = UUID().uuidString
        tempAlarm.onSnooze = false
        if segueInfo.isEditMode {
            alarmModel.alarms[index] = tempAlarm
        }
        else {
            alarmModel.alarms.append(tempAlarm)
        }
        self.performSegue(withIdentifier: Id.saveSegueIdentifier, sender: self)
    }


    func numberOfSections(in tableView: UITableView) -> Int {
        // Return the number of sections.
        if segueInfo.isEditMode {
            return 2
        }
        else {
            return 1
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return 5
        }
        else {
            return 1
        }
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell = tableView.dequeueReusableCell(withIdentifier: Id.settingIdentifier)
        if(cell == nil) {
            cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: Id.settingIdentifier)
        }
        if indexPath.section == 0 {

            if indexPath.row == 0 {

                cell!.textLabel!.text = "Repeat"
                cell!.detailTextLabel!.text = WeekdaysViewController.repeatText(weekdays: segueInfo.repeatWeekdays)
                cell!.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
            }
            else if indexPath.row == 1 {
                cell!.textLabel!.text = "Label"
                cell!.detailTextLabel!.text = segueInfo.label
                cell!.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
            }
            else if indexPath.row == 2 {
                cell!.textLabel!.text = "Sound"
                cell!.detailTextLabel!.text = segueInfo.mediaLabel
                cell!.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
            }
            else if indexPath.row == 3 {
                cell!.textLabel!.text = "Route"
                cell!.detailTextLabel!.text = segueInfo.routeLabel
                cell!.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
            }
//            else if indexPath.row == 3 {
            else if indexPath.row == 4 {

                cell!.textLabel!.text = "Snooze"
                let sw = UISwitch(frame: CGRect())
                sw.addTarget(self, action: #selector(AlarmAddEditViewController.snoozeSwitchTapped(_:)), for: UIControlEvents.touchUpInside)

                if snoozeEnabled {
                    sw.setOn(true, animated: false)
                }

                cell!.accessoryView = sw
            }
        }
        else if indexPath.section == 1 {
            cell = UITableViewCell(
                style: UITableViewCellStyle.default, reuseIdentifier: Id.settingIdentifier)
            cell!.textLabel!.text = "Delete Alarm"
            cell!.textLabel!.textAlignment = .center
            cell!.textLabel!.textColor = UIColor.red
        }

        return cell!
    }


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath)
        if indexPath.section == 0 {
            switch indexPath.row{
            case 0:
                performSegue(withIdentifier: Id.weekdaysSegueIdentifier, sender: self)
                cell?.setSelected(true, animated: false)
                cell?.setSelected(false, animated: false)
            case 1:
                performSegue(withIdentifier: Id.labelSegueIdentifier, sender: self)
                cell?.setSelected(true, animated: false)
                cell?.setSelected(false, animated: false)
            case 2:
                performSegue(withIdentifier: Id.soundSegueIdentifier, sender: self)
                cell?.setSelected(true, animated: false)
                cell?.setSelected(false, animated: false)
            case 3:
                performSegue(withIdentifier: Id.routeSegueIdentifier, sender: self)
                cell?.setSelected(true, animated: false)
                cell?.setSelected(false, animated: false)
            default:
                break
            }
        }
        else if indexPath.section == 1 {
            //delete alarm
            alarmModel.alarms.remove(at: segueInfo.curCellIndex)
            performSegue(withIdentifier: Id.saveSegueIdentifier, sender: self)
        }

    }

    @IBAction func snoozeSwitchTapped (_ sender: UISwitch) {
        snoozeEnabled = sender.isOn
    }


    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
        if segue.identifier == Id.saveSegueIdentifier {
            let dist = segue.destination as! MainAlarmViewController
            let cells = dist.tableView.visibleCells
            for cell in cells {
                let sw = cell.accessoryView as! UISwitch
                if sw.tag > segueInfo.curCellIndex
                {
                    sw.tag -= 1
                }
            }
            alarmScheduler.reSchedule()
        }
        else if segue.identifier == Id.soundSegueIdentifier {
            //TODO
            let dist = segue.destination as! MediaViewController
            dist.mediaID = segueInfo.mediaID
            dist.mediaLabel = segueInfo.mediaLabel
        }
        else if segue.identifier == Id.labelSegueIdentifier {
            let dist = segue.destination as! LabelEditViewController
            dist.label = segueInfo.label
        }
        else if segue.identifier == Id.weekdaysSegueIdentifier {
            let dist = segue.destination as! WeekdaysViewController
            dist.weekdays = segueInfo.repeatWeekdays
        }
        else if segue.identifier == Id.routeSegueIdentifier {
            let dist = segue.destination as! RouteTableViewController
            dist.routeLabel = segueInfo.routeLabel

        }
    }

    @IBAction func unwindFromLabelEditView(_ segue: UIStoryboardSegue) {
        let src = segue.source as! LabelEditViewController
        segueInfo.label = src.label
    }

    @IBAction func unwindFromWeekdaysView(_ segue: UIStoryboardSegue) {
        let src = segue.source as! WeekdaysViewController
        segueInfo.repeatWeekdays = src.weekdays
    }

    @IBAction func unwindFromMediaView(_ segue: UIStoryboardSegue) {
        let src = segue.source as! MediaViewController
        segueInfo.mediaLabel = src.mediaLabel
        segueInfo.mediaID = src.mediaID
    }
    @IBAction func unwindFromRouteView(_ segue: UIStoryboardSegue) {
        let src = segue.source as! RouteTableViewController
        segueInfo.routeLabel = src.routeLabel
//        segueInfo.routeId = src.routeId

    }


}

and a working VC unwind example:

class LabelEditViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var labelTextField: UITextField!
    var label: String!

    override func viewDidLoad() {
        super.viewDidLoad()
        labelTextField.becomeFirstResponder()
        // Do any additional setup after loading the view.
        self.labelTextField.delegate = self

        labelTextField.text = label

        //defined in UITextInputTraits protocol
        labelTextField.returnKeyType = UIReturnKeyType.done
        labelTextField.enablesReturnKeyAutomatically = true
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        label = textField.text!
        performSegue(withIdentifier: Id.labelUnwindIdentifier, sender: self)
        //This method can be used when no state passing is needed
        //navigationController?.popViewController(animated: true)
        return false
    }

}

I did connect the unwind as usual and in the inspector it looks like it's connected as other tableVC or labelVC.

unwind from route tableVC

unwind from other tableVC

unwind from labelVC

Can you see what's the problem with the RouteTableVIewController ?

Vincenzo
  • 5,304
  • 5
  • 38
  • 96

1 Answers1

1

You haven't assigned the identifier to the unwind segue.

To fix that:

  1. Find Unwind segue to "unwindFromRouteView:" in the Document Outline view. (To open the Document Outline view, click on the icon to the left of View as: iPhone 8 (wC hR) in the Storyboard below your ViewController). Select the unwind segue by clicking on it.
  2. In the Attributes Inspector on the right, set the Identifier field to routeUnwindSegue.
  3. Back in the Document Outline view, the segue should now read: Unwind segue "routeUnwindSegue" to "unwindFromRouteView:".
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • 1
    @vacaæama. Yes that was it! I couldn't see it. Thank you so much. It now does work as expected. I'm still learning swift and some of this basic stuff I seem not to have it under my belt yet. Thank you again. – Vincenzo Aug 23 '18 at 20:52