簡體   English   中英

頁面視圖中的子視圖控制器 Controller 無法接收委托呼叫

[英]Child View Controllers in Page View Controller Failing to Receive Delegate Calls

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

}

抱歉,這太冗長了,已經嘗試了很長一段時間,真的很生氣,因為它不起作用! 謝謝!

我會盡量說清楚,希望我會這樣,因為英語不是我的母語。

在我看來,您正在實例化您的 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組成,該 PageController 顯示一個帶有紅色按鈕的buttonsVC和一個帶有藍色背景的displayMaplessVC 按下紅色按鈕后,將調用委托方法,使藍色背景變為綠色。
看看我在做什么,因為我附加了我設置委托的相同實例:

  1. 實例化 DisplayMaplessViewController object 和 ButtonsViewController object;
  2. 設置buttonsVC.buttonsDelegate = displayMaplessVC ;
  3. append 兩個 ViewControllers 到數組。

這是完成它的一種方法,但可以肯定的是,還有其他幾種方法可以達到相同的結果,一旦您明白了要點並了解了自己的錯誤,就可以選擇最喜歡的一種。

只需將其復制並粘貼到一個新項目中,構建並運行(您必須將 Storyboard 中的起始 ViewController 的 class 設置為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
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM