在 UIPageViewController 中包含的 ViewController 的委托获得 nil

Posted

技术标签:

【中文标题】在 UIPageViewController 中包含的 ViewController 的委托获得 nil【英文标题】:Got nil for delegate at ViewController included in UIPageViewController 【发布时间】:2019-12-22 18:19:52 【问题描述】:

我有一个UIPageViewController 和几个ViewControllers。我想使用委托协议从ViewControllerUIPageViewController 中执行一个功能。但是在delegate 中获取nil。谁能确定我做错了什么?

PageViewController.swift

import UIKit

class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource, Storyboarded 


    weak var coordinator: MainCoordinator?

    lazy var orderedViewControllers: [UIViewController] = 
        return [self.newInstanceVC(viewController: "FirstLoadViewController"), self.newInstanceVC(viewController: "FirstLoad2ViewController")]
    ()

    var pageControl = UIPageControl()

    override func viewDidLoad() 
        super.viewDidLoad()

        let storyboardVC = newInstanceVC(viewController: "FirstLoad2ViewController") as? FirstLoad2ViewController
        storyboardVC?.delegate = self

        self.dataSource = self
        if let firstViewController = orderedViewControllers.first 
            setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil)
        

        self.delegate = self
        configurePageControl()
    


    func configurePageControl() 
        pageControl = UIPageControl(frame: CGRect(x: 0, y: UIScreen.main.bounds.maxY - 50, width: UIScreen.main.bounds.width, height: 50))
        pageControl.numberOfPages = orderedViewControllers.count
        pageControl.currentPage = 0
        //pageControl.tintColor = .red
        pageControl.pageIndicatorTintColor = .systemGray5
        pageControl.currentPageIndicatorTintColor = .systemGray
        self.view.addSubview(pageControl)
    



        //return view controller by string identifier
    func newInstanceVC(viewController: String) -> UIViewController 
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: viewController)
    


//MARK: - Setup page controllers

        // view controller that appears on swiping to the -> (left)
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? 

        guard let viewControllerIndex = orderedViewControllers.firstIndex(of: viewController) else 
            return nil
        

        let previousIndex = viewControllerIndex - 1

        guard previousIndex >= 0 else 
            //return view controller from the end if it is last index from the left side (infinit scroll)
            //return orderedViewControllers.last
            return nil
        

        guard orderedViewControllers.count >= previousIndex else 
            return nil
        


        return orderedViewControllers[previousIndex]
    

        // view controller that appears on swiping to the <- (right)
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? 

        guard let viewControllerIndex = orderedViewControllers.firstIndex(of: viewController) else 
            return nil
        

        let nextIndex = viewControllerIndex + 1

        guard orderedViewControllers.count != nextIndex else 
            //return view controller from the begining if it is last index from the right side (infinit scroll)
            //return orderedViewControllers.first
            return nil
        

        guard orderedViewControllers.count > nextIndex else 
            return nil
        

        return orderedViewControllers[nextIndex]
    

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
            //switch the bullet of the page
        let pageContentVievController = pageViewController.viewControllers![0]
        self.pageControl.currentPage = orderedViewControllers.firstIndex(of: pageContentVievController)!
    




extension PageViewController: PageViewDelegate 
    func handleButtonTap() 
        coordinator?.goToMainFromPresentation()
    



OneOfTheViewControllers.swift

import UIKit


protocol PageViewDelegate: class 
    func handleButtonTap()






class FirstLoad2ViewController: UIViewController, Storyboarded 


    weak var coordinator: MainCoordinator?
    weak var child: ChildCoordinator?

    weak var delegate: PageViewDelegate?

    override func viewDidLoad() 
        super.viewDidLoad()



    

    @IBAction func toMainScreenTap(_ sender: Any) 
        delegate!.handleButtonTap() //got nil for delegate here
    


【问题讨论】:

【参考方案1】:

问题很简单,它隐藏在你的viewDidLoad()方法里面PageViewController

...

override func viewDidLoad() 
    super.viewDidLoad()

    let storyboardVC = newInstanceVC(viewController: "FirstLoad2ViewController") as? FirstLoad2ViewController
    storyboardVC?.delegate = self

       ...

/// (storyboardVC) --- will be destroyed when out of viewDidLoad() scope.

那么,为什么你得到你的storyboardVC?.delegate = self nil?因为您在 viewDidLoad() 方法中创建了 storyboardVC 属性,并且没有任何东西保留对它的引用。所以,最后 viewDidLoad() 方法它只是取消初始化以及它的 PageViewDelegate delegate

【讨论】:

好的。您对修复的建议是什么? @OlehH 我的建议是快速阅读有关内存管理的内容,这将对您有所帮助:docs.swift.org/swift-book/LanguageGuide/…

以上是关于在 UIPageViewController 中包含的 ViewController 的委托获得 nil的主要内容,如果未能解决你的问题,请参考以下文章

在其中一个页面中包含的 UISwitch 上开始触摸时禁用 UIPageViewController 滚动

iOS - 如何在 UIPageViewController 中设置 UIScrollView 以在重新启用后开始滚动

从 UIPageViewContoller 中包含的视图设置 UINavigationBar 标题

UIPageControl(页面控件)不显示在 UIPageViewController

ViewDidLoad 不断在 UIPageViewController 上被调用

UIPageViewController 背景在 Objective C iOS 中从不透明