You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Segue执行成功但界面未切换?iOS开发问题排查

自定义Alert执行Segue后界面无变化,但目标VC的viewDidLoad已执行

尝试通过Segue将自定义Alert中的用户输入传递到目标页面,执行Segue后应用界面未发生变化,但目标ViewController的viewDidLoad方法已正常运行(通过打印语句确认)。

详细信息

涉及3个类:STAlert(自定义Alert)、WorkoutLibraryViewController(初始ViewController)、STAddExerciseViewController(目标ViewController)。
WorkoutLibraryViewController与STAddExerciseViewController通过Identifier为"addWorkout"的show segue在Storyboard中关联。使用Xcode 15.4版本,基于Storyboard开发。

WorkoutLibraryViewController类代码

import UIKit

class WorkoutLibraryViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{

    @IBOutlet weak var WorkoutList: UITableView!
    var workouts:[Workout] = []
    let customAlert = STAlerts()
    @IBOutlet weak var addWorkoutButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        WorkoutList.delegate = self
        WorkoutList.dataSource = self
        view.backgroundColor = Colors.navyBlue
        // Do any additional setup after loading the view.
    }
    
    @IBAction func didTapCreateWorkout(_ sender: Any) {
        customAlert.showAlert(with: "hello world", messege: "name?", on: self)
        print("workoutBTN")
    }
    
    @objc func didTapDoneAlert(){
        customAlert.didTapDoneAlert()
        print("Did Tap Done")
    }
   
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "addWorkout"{
            if let destinationVC = segue.destination as? STAddExerciseViewController {
                destinationVC.workoutName = customAlert.userInput
                print("preformed Seguea to \(destinationVC) WorkoutViewController")
            }
            else{
                print("DestinationVC not set")
            }
        }else{
            print("Couldn't find segue identifier")
        }
    }
    /*
    // 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.destination.
        // Pass the selected object to the new view controller.
    }
    */
    // MARK: - UITableViewDataSource Methods
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         return workouts.count
     }
     
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: "WorkoutCell", for: indexPath)
         let workout = workouts[indexPath.row]
         cell.textLabel?.text = workout.name
         // Configure the cell as needed
         return cell
     }
     
     // MARK: - UITableViewDelegate Methods
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         // Handle row selection
     }
}

STAlert类代码

import Foundation
import UIKit

class STAlerts: NSObject, UITextFieldDelegate{

    private var backgroundView: UIView = {
        let backgroundView = UIView()
        backgroundView.backgroundColor = .black
        backgroundView.alpha = 0
        return backgroundView
    }()
    
    private let alertView: UIView = {
        let alert = UIView()
        alert.backgroundColor = Colors.greyBlue
        alert.layer.masksToBounds = true
        alert.layer.cornerRadius = 12
        return alert
    }()
    
    private var myTargetView:UIView?
    var userInput: String? // user input value
    
    
    func showAlert(with title:String, messege:String, on viewController: UIViewController){
        
        guard let targetView = viewController.view else {
            return
        }
        myTargetView = targetView
        backgroundView.frame = targetView.bounds
        targetView.addSubview(backgroundView)
       
        targetView.addSubview(alertView)
        alertView.frame = CGRect(x: 40, y: -300 , width: targetView.frame.size.width-80, height: 300)
        
      
        
        let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: alertView.frame.size.width, height: 80))
        
        titleLabel.text = title
        titleLabel.textColor = Colors.white
        titleLabel.textAlignment =  .center
        alertView.addSubview(titleLabel)
        
        let msgLabel = UILabel(frame: CGRect(x: 0, y: titleLabel.frame.minY + 10, width: alertView.frame.size.width, height: 80))
        
        msgLabel.numberOfLines = 0
        msgLabel.text = messege
        msgLabel.textColor = Colors.white
        msgLabel.textAlignment =  .center
        alertView.addSubview(msgLabel)
        //<-------------------textField---------------->
        
        let textField = STTextField(frame: CGRect(x: 0, y: msgLabel.frame.maxY + 10 , width: alertView.frame.size.width-10, height: 20))
     
        
        textField.delegate = self // set Delegate
     
        textField.placeholder = {
            let placeHolders:[String] = ["Push & Pull Split", "Arm Day", "Bodyweight Routine"]
            return placeHolders[Int.random(in: 0..<placeHolders.count)]
        }()
        
        func textFieldShouldReturn(_ textField: STTextField) -> Bool {
            textField.resignFirstResponder()
                return true
            }

        
        alertView.addSubview(textField)
        
      // <---------------------button------------------->
        let button = UIButton(frame: CGRect(x: 0,
                                            y: alertView.frame.size.height-50,
                                            width: alertView.frame.size.width,
                                            height: 50))
        
        alertView.addSubview(button)
        button.setTitle("Done", for: .normal)
        button.setTitleColor(Colors.energyOrange, for: .normal)
        button.addTarget(self, action: #selector(didTapDoneAlert), for:.touchUpInside)
        
        
        UIView.animate(withDuration: 0.25, animations: {
          
            self.backgroundView.alpha = 0.6
            
        }, completion: { done in
            if done{
                UIView.animate(withDuration: 0.25, animations: {
                    self.alertView.center = targetView.center                })
    
            }
        })
    }
    
    @objc func didTapDoneAlert(){
        guard let targetView = myTargetView else{
            print("Error: targetView is nil")
            return
        }
        
        UIView.animate(withDuration: 0.25, animations: {
          self.alertView.frame = CGRect(x: 40, y: -300 , width: targetView.frame.size.width-80, height: 300)
        }, 
        completion:{ done in
            if done{
                UIView.animate(withDuration: 0.25, animations: {
                    self.backgroundView.alpha = 0
                },
                completion: {done in
                    if done{
                        self.backgroundView.removeFromSuperview()
                        self.alertView.removeFromSuperview()
                        if let viewController = targetView.parentViewController() as? WorkoutLibraryViewController {
                            print("Segue performed on view controller: \(viewController) AlertView")
                            viewController.performSegue(withIdentifier: "addWorkout", sender: self)
                        }else{
                            print("Error: Unable to find view controller to perform segue")
                        }
                        
                    }})
            }
        })
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        userInput = textField.text?.isEmpty == true ? textField.placeholder : textField.text
            return true
    }
    
    //<-------------------- Navigation --------------->
    
}
extension UIView {
    func parentViewController() -> UIViewController? {
        var parentResponder: UIResponder? = self
        while let responder = parentResponder {
            parentResponder = responder.next
            if let viewController = responder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

STAddExerciseViewController类代码

import UIKit

class STAddExerciseViewController: UIViewController, UITableViewDataSource, STExerciseTableViewCellDelegate {
   
    @IBOutlet weak var searchBar: UISearchBar!
    
    @IBOutlet weak var workoutTitle: UILabel!
    
    @IBOutlet weak var doneBtn: UIButton!
    
    @IBOutlet weak var table: UITableView!
    
    var workoutName:String?
    
    var filter:[Exercise]!
    
    var newExercises:[Exercise] = []
    
    var exercises:[Exercise] = [Exercise(name: "Pushup", video: "pushup"), Exercise(name: "Pullup", video: "pullup"), Exercise(name: "Situp", video: "situp"), Exercise(name: "Bicep Curl", video: "bicepcurl" ), Exercise(name: "Hammer Curl", video: "hammercurl"), Exercise(name: "Barbell Curl", video: "barbellcurl"), Exercise(name: "Inclined Dumbell Curl", video: "inclinedcurl"), Exercise(name: "Spider Curl", video: "spidercurl"), Exercise(name: "Squat", video: "squat"),Exercise(name: "DeadLift", video: "deadlift"), Exercise(name: "Crunch", video: "crunch"), Exercise(name: "Russian Twist", video: "russiantwist")]
   
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("Adding workout")
        self.view.backgroundColor = Colors.navyBlue
        filter = exercises
        workoutTitle.text = workoutName
        table.register(STExerciseTableViewCell.nib(), forCellReuseIdentifier: STExerciseTableViewCell.identifier)
        table.dataSource = self
        while newExercises.count == 0{
                    doneBtn.titleLabel?.text = "Cancel"
        }
        
        // Do any additional setup after loading the view.
    }
    
    func didTapButton(with exercise: Exercise) {
        print(exercise.name)
        for i in 0..<newExercises.count{
            if newExercises[i].name == exercise.name{
                newExercises.remove(at: i)
            }
            else{
                newExercises.append(exercise)
            }
        }
        doneBtn.titleLabel?.text = "Add \(newExercises.count) Exercises"
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return exercises.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: STExerciseTableViewCell.identifier, for: indexPath) as! STExerciseTableViewCell
        cell.configure(with: exercises[indexPath.row])
        
        cell.delegate = self
        return cell
    }

    
    @IBAction func didTapDone(_ sender: Any) {
        func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            // Get the new view controller using segue.destination.
            // Pass the selected object to the new view controller.
        }
    }
    
    
    
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    
    */

}

当前控制台输出

Segue performed on view controller:
<StrengthTree_JSM_.WorkoutLibraryViewController: 0x10d9076a0> AlertView
preformed Seguea to <StrengthTree_JSM_.STAddExerciseViewController: 0x10db3c9e0> WorkoutViewController
nw_connection_copy_connected_local_endpoint_block_invoke [C1] Connection has no local endpoint
nw_connection_copy_connected_local_endpoint_block_invoke [C1] Connection has no local endpoint
Adding workout
nw_connection_copy_connected_local_endpoint_block_invoke [C1] Connection has no local endpoint

内容的提问来源于stack exchange,提问作者Samuel Mensah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:19:50