Ios 页面视图控制器中的子视图控制器无法接收委托调用

Ios 页面视图控制器中的子视图控制器无法接收委托调用,ios,swift,delegates,protocols,uipageviewcontroller,Ios,Swift,Delegates,Protocols,Uipageviewcontroller,我在父PageViewController中的两个子视图控制器出现问题,其中一个子视图控制器调用的委托未被另一个子视图控制器接收 我的第一个孩子包含按钮,当按下一个按钮时,会在另一个孩子中触发一个代理以暂停计时器。但是,它无法接收呼叫,计时器继续运行 这是我的PageViewController: class StartMaplessWorkoutPageViewController: UIPageViewController, UIPageViewControllerDelegate, UIP

我在父PageViewController中的两个子视图控制器出现问题,其中一个子视图控制器调用的委托未被另一个子视图控制器接收

我的第一个孩子包含按钮,当按下一个按钮时,会在另一个孩子中触发一个代理以暂停计时器。但是,它无法接收呼叫,计时器继续运行

这是我的PageViewController:

class StartMaplessWorkoutPageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {

    lazy var workoutViewControllers: [UIViewController] = {
        return [self.getNewViewController(viewController: "ButtonsViewController"), self.getNewViewController(viewController: "DisplayMaplessViewController")]
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.dataSource = self
        
        // Saw this from another answer, doesn't do anything that helps (at the moment)
        let buttonsViewController = storyboard?.instantiateViewController(withIdentifier: "ButtonsViewController") as! ButtonsViewController
        let displayMaplessViewController = storyboard?.instantiateViewController(withIdentifier: "DisplayMaplessViewController") as! DisplayMaplessViewController
        
        buttonsViewController.buttonsDelegate = displayMaplessViewController
        
        if let firstViewController = workoutViewControllers.last {
            setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil)
        }
        
        let pageControl = UIPageControl.appearance(whenContainedInInstancesOf: [StartWorkoutPageViewController.self])
        pageControl.currentPageIndicatorTintColor = .orange
        pageControl.pageIndicatorTintColor = .gray
    }
    
    func getNewViewController(viewController: String) -> UIViewController {
        return (storyboard?.instantiateViewController(withIdentifier: viewController))!
    }
    
    // MARK: PageView DataSource
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = workoutViewControllers.firstIndex(of: viewController) else {
            return nil
        }
        
        let previousIndex = viewControllerIndex - 1
        
        guard previousIndex >= 0 else {
            return workoutViewControllers.last
        }
        
        guard workoutViewControllers.count > previousIndex else {
            return nil
        }
        
        return workoutViewControllers[previousIndex]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = workoutViewControllers.firstIndex(of: viewController) else {
            return nil
        }
        
        let nextIndex = viewControllerIndex + 1
        let workoutViewControllersCount = workoutViewControllers.count
        
        guard workoutViewControllersCount != nextIndex else {
            return workoutViewControllers.first
        }
        
        guard workoutViewControllersCount > nextIndex else {
            return nil
        }
        
        return workoutViewControllers[nextIndex]
    }
    
    func presentationCount(for pageViewController: UIPageViewController) -> Int {
        return workoutViewControllers.count
    }
    
    func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        guard let firstViewController = viewControllers?.first, let firstViewControllerIndex = workoutViewControllers.firstIndex(of: firstViewController) else {
            return 0
        }
        
        return firstViewControllerIndex
    }
}
带按钮的My ChildViewController:

protocol ButtonsViewDelegate: class {
    func onButtonPressed(button: String)
}

class ButtonsViewController: UIViewController {
    
    weak var buttonsDelegate: ButtonsViewDelegate?
    
    var isPaused: Bool = false
    
    @IBOutlet weak var startStopButton: UIButton!
    @IBOutlet weak var optionsButton: UIButton!
    @IBOutlet weak var endButton: UIButton!
    
    @IBAction func startStopButton(_ sender: Any) {
        if isPaused == true {
            buttonsDelegate?.onButtonPressed(button: "Start")
            isPaused = false
        } else {
            buttonsDelegate?.onButtonPressed(button: "Pause")
            isPaused = true
        }
    }
    
    @IBAction func endButton(_ sender: Any) {
        let menu = UIAlertController(title: "End", message: "Are you sure you want to end?", preferredStyle: .actionSheet)
        
        let end = UIAlertAction(title: "End", style: .default, handler: { handler in
            self.buttonsDelegate?.onButtonPressed(button: "End")
        })
        
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
        menu.addAction(end)
        menu.addAction(cancelAction)
        
        self.present(menu, animated: true, completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

我的另一个ChildViewController,它应该接收ButtonsViewDelegate的调用:

import UIKit

class DisplayMaplessViewController: UIViewController, ButtonsViewDelegate {
    
    var timer = Timer()
    var currentTime: TimeInterval = 0.0
    var isCountdown: Bool = false
    var isInterval: Bool = false
    var currentRepeats: Int = 0
    var currentActivity: Int = 0
    var count: Int = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        startIntervalTimer(withTime: 0)
    }

    // Currently not being called
    func onButtonPressed(button: String) {
        switch button {
        case "Start":
            restartIntervalTimer()
        case "Pause":
            pauseIntervalTimer()
        case "End":
            stop()
        default:
            break
        }
    }
    
    func startIntervalTimer(withTime: Double) {
        if withTime != 0 {
            currentTime = withTime
            if isInterval != true {
                isCountdown = true
            }
        }

        timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(intervalTimerUpdate), userInfo: nil, repeats: true)
    }
    
    func pauseIntervalTimer() {
        timer.invalidate()
    }
    
    func restartIntervalTimer() {
        timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(intervalTimerUpdate), userInfo: nil, repeats: true)
    }

    // Currently Not being called
    func stop() {
        timer.invalidate()
        let formatter = DateComponentsFormatter()
        formatter.unitsStyle = .positional
        formatter.allowedUnits = [.hour, .minute, .second]
        formatter.zeroFormattingBehavior = [.pad]
        
        let timeString = formatter.string(from: currentTime)
        
        // save the data etc

        print("Stop is called")
    }
    
    @objc func intervalTimerUpdate() {
        currentTime += 1.0
        print(currentTime)
    }

}

抱歉,这是这么冗长,已经尝试了很长一段时间,真的很恼火,它不工作!谢谢

我会尽量说清楚,希望我能说清楚,因为英语不是我的母语

在我看来,您正在实例化要在
getNewViewController()
方法中显示的ViewController,并将它们存储在
WorkoutViewController
数组中,但您正在将委托设置为一个单独的实例,而您从未在PageVC中设置过。您需要使用相同的实例设置代理

这两个是两个VC类的两个实例(也不确定标识符“DisplayViewController”是否正确,我希望是“DisplayMaplessViewController”,没有情节提要很难说):

数组中的这两个实例是相同的两个类的另两个实例,与上面的实例无关:

    lazy var workoutViewControllers: [UIViewController] = {
    return [self.getNewViewController(viewController: "ButtonsViewController"), self.getNewViewController(viewController: "DisplayMaplessViewController")]
}()
为了更好地理解我的意思,我从头开始重构并重组了您的项目(必须以编程方式进行,因为我不习惯故事板)。 它现在由一个
PageController
组成,该控制器显示一个带有红色按钮的
按钮VC
,以及一个带有蓝色背景的
displayMaplessVC
。 按下红色按钮后,将调用委托方法,使蓝色背景变为绿色。
看看我在做什么,因为我在附加我设置委托的相同实例:

  • 实例化DisplayMaplessViewController对象和ButtonsViewController对象
  • 设置按钮VC.buttonsDelegate=displayMaplessVC
  • 将两个ViewController追加到阵列
  • 这是一种完成任务的方法,但可以肯定的是,还有其他几种方法可以达到同样的效果,一旦你抓住要点并理解错误,你就可以选择你最喜欢的方法

    只需将其复制并粘贴到一个新项目中,构建并运行(您必须将故事板中启动的ViewController的类设置为
    startMaplesWorkoutPageViewController
    ):


    你好谢谢你。我已经为你指出的打字错误更新了上面的代码(哎呀!)。它现在开始工作了!谢谢
        lazy var workoutViewControllers: [UIViewController] = {
        return [self.getNewViewController(viewController: "ButtonsViewController"), self.getNewViewController(viewController: "DisplayMaplessViewController")]
    }()
    
    import UIKit
    
    class StartMaplessWorkoutPageViewController: UIViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
    
    private var workoutViewControllers = [UIViewController]()
    private let pageController: UIPageViewController = {
        let pageController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        return pageController
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        pageController.delegate = self
        pageController.dataSource = self
        let buttonsVC = ButtonsViewController()
        let displayMaplessVC = DisplayMaplessViewController()
        buttonsVC.buttonsDelegate = displayMaplessVC
        workoutViewControllers.append(buttonsVC)
        workoutViewControllers.append(displayMaplessVC)
        
        self.addChild(self.pageController)
        self.view.addSubview(self.pageController.view)
    
        self.pageController.setViewControllers([displayMaplessVC], direction: .forward, animated: true, completion: nil)
    
        self.pageController.didMove(toParent: self)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        pageController.view.frame = view.bounds
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        
        guard let viewControllerIndex = workoutViewControllers.firstIndex(of: viewController) else {
             return nil
         }
         
         let previousIndex = viewControllerIndex - 1
         
         guard previousIndex >= 0 else {
             return workoutViewControllers.last
         }
         
         guard workoutViewControllers.count > previousIndex else {
             return nil
         }
         
         return workoutViewControllers[previousIndex]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        
        guard let viewControllerIndex = workoutViewControllers.firstIndex(of: viewController) else {
            return nil
        }
        
        let nextIndex = viewControllerIndex + 1
        let workoutViewControllersCount = workoutViewControllers.count
        
        guard workoutViewControllersCount != nextIndex else {
            return workoutViewControllers.first
        }
        
        guard workoutViewControllersCount > nextIndex else {
            return nil
        }
        
        return workoutViewControllers[nextIndex]
    }
    
    func presentationCount(for pageViewController: UIPageViewController) -> Int {
        return workoutViewControllers.count
    }
    
    }
    
    protocol ButtonsViewDelegate: class {
        func onButtonPressed()
    }
    
    import UIKit
    
    class ButtonsViewController: UIViewController {
    
    weak var buttonsDelegate: ButtonsViewDelegate?
    
    let button: UIButton = {
        let button = UIButton()
        button.backgroundColor = .red
        button.addTarget(self, action: #selector(onButtonPressed), for: .touchUpInside)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(button)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        button.frame = CGRect(x: 50,
                              y: 50,
                              width: 100,
                              height: 100)
    }
    
    @objc private func onButtonPressed() {
        buttonsDelegate?.onButtonPressed()
    }
    
    }
    
    import UIKit
    
    class DisplayMaplessViewController: UIViewController, ButtonsViewDelegate {
    
    private let testView: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(testView)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        testView.frame = view.bounds
    }
    
    internal func onButtonPressed() {
        testView.backgroundColor = .green
    }
    
    }