如何解决页面视图控制器中的子视图控制器无法接收委托调用
我在父 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,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,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)
}
}
很抱歉,这太啰嗦了,已经尝试了很长时间,但真的很生气,因为它不起作用!谢谢!
解决方法
我会尽量说清楚,希望我能做到,因为英语不是我的母语。
在我看来,您正在实例化您的 ViewControllers 以在 getNewViewController()
方法中呈现并将它们存储在 workoutViewControllers
数组中,但是您将委托设置为一个您从未设置过的单独实例在您的 PageVC 中。您需要使用相同的实例设置委托。
这两个是两个 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
显示一个带有红色按钮的 displayMaplessVC
和一个带有蓝色背景的 buttonsVC.buttonsDelegate = displayMaplessVC
。
按下红色按钮后,将调用委托方法,使蓝色背景变为绿色。
看看我在做什么,因为我正在附加我设置委托的相同实例:
- 实例化一个 DisplayMaplessViewController 对象和 ButtonsViewController 对象;
- 设置
StartMaplessWorkoutPageViewController
; - 将两个 ViewController 附加到数组中。
这是完成任务的一种方式,但可以肯定的是,还有其他几种方法可以实现相同的结果,一旦您明白了自己的错误,就可以选择您最喜欢的方式。
只需将其复制并粘贴到新项目中,构建并运行即可(您必须将 Storyboard 中起始 ViewController 的类设置为 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
}
}
.
inject
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。