从 tableview 展开时未找到展开 segue Swift

Unwind segue is not found when unwinding from tableview Swift

我在从 RouteTableViewController 放松到 AlarmAddEditViewController 时遇到了崩溃。在控制台中,我看到消息:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<fix_it_mapView.RouteTableViewController: 0x7ffad352e4a0>) has no segue with identifier 'routeUnwindSegue''.

这里其实声明为另一个表VC:

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"

} 

这是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
    }


}

这是 À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

    }


}

和一个有效的VC展开示例:

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
    }

}

我确实像往常一样连接了 unwind,在检查器中它看起来像连接了其他表VC 或标签VC。

你能看出 RouteTableVIewController 有什么问题吗?

您尚未将标识符分配给展开转场。

解决这个问题:

  1. 文档大纲 视图中找到 Unwind segue to "unwindFromRouteView:"。 (要打开 文档大纲 视图,请单击 ViewController 下方情节提要中 View as: iPhone 8 (wC hR) 左侧的图标)。 Select 通过点击展开转场。
  2. 在右侧的 Attributes Inspector 中,将 Identifier 字段设置为 routeUnwindSegue
  3. 返回 文档大纲 视图,segue 现在应该显示为:Unwind segue "routeUnwindSegue" to "unwindFromRouteView:".