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

安东尼

我在父级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
    }
}

我的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并将它们存储在workoutViewControllers数组中,但是您正在将委托设置为一个从未在PageVC中设置的单独实例。您需要使用相同的实例设置委托。

这两者是两个实例2 VC(也不能肯定是否标识符“DisplayViewController”是正确的,我预计“DisplayMaplessViewController”,很难说没有故事板):

    let buttonsViewController = storyboard?.instantiateViewController(withIdentifier: "ButtonsViewController") as! ButtonsViewController
    let displayMaplessViewController = storyboard?.instantiateViewController(withIdentifier: "DisplayViewController") as! DisplayMaplessViewController
    
    buttonsViewController.buttonsDelegate = displayMaplessViewController

这些在数组中与上述两个实例无关的另外两个实例相同的两个类

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

为了更好地理解我的意思,我从头开始重构并简化了您的项目(因为我不习惯情节提要,因此必须以编程方式进行)。现在,它由PageController显示一个buttonsVC带有红色按钮的a和一个displayMaplessVC具有蓝色背景的a组成。按下红色按钮后,将调用委托方法,该方法将使蓝色背景变为绿色。
看看我在做什么,因为我要追加设置委托的相同实例:

  1. 实例化DisplayMaplessViewController对象和ButtonsViewController对象;
  2. 设置buttonsVC.buttonsDelegate = displayMaplessVC;
  3. 将两个ViewController附加到数组。

这是完成任务的一种方法,但是可以肯定的是,还有其他几种方法可以达到相同的结果,一旦您掌握了要点并理解了错误,就可以选择最喜欢的一个。

只需将其复制并粘贴到新项目中,然后构建并运行(您必须在Storyboard中将启动ViewController的类设置为StartMaplessWorkoutPageViewController):

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
}

}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

从多个视图控制器接收委托方法调用

无法删除子视图控制器

使用委托从模态视图控制器调用另一个视图控制器中的方法

页面视图控制器更新视图控制器?

子视图控制器中的topLayoutGuide

UICollectionViewCell中的子视图控制器

从委托类调用视图控制器函数

从视图控制器调用应用程序委托方法

容器视图控制器之间的委托

通过视图控制器的AppCoordinator委托

使用分段控制操作调用子视图控制器?

从父视图控制器调用子视图实例的功能

如何从嵌入在父视图控制器的子视图控制器中的UISearchViewController提供视图控制器?

动画子视图控制器视图

子视图控制器的viewDidLoad在父视图控制器的之前被调用?

在标签栏控制器内的所有继承的视图控制器中,BaseController委托无法正常工作

在子视图控制器中调整滚动视图的插入

子视图控制器的视图未显示在容器中

将子视图控制器链接到情节提要中的父视图控制器

如何从父视图控制器中快速修改子视图控制器的对象

如何在应用程序委托的视图控制器中调用方法?

ios viewcontroller 在容器内调用子视图控制器

AngularJS:子视图的控制器从不调用

iOS | 无法在应用程序委托中更改根视图控制器

Swift 从视图控制器调用类

从 TabBarClass 调用视图控制器方法

如何从控制器调用视图组件

在视图中调用控制器方法

从ajax控制器调用更新视图