Search code examples
iosswiftxcodeuipageviewcontroller

Can't reload next ViewController in PageViewController


I can't update next page in my PageViewController.

  1. I add the required number of controllers, but the pageController.setViewControllers([controllers[0]], direction: .forward, animated: false) method leaves us with one.

  2. I have information for each next controller taken from the viewModel and updated when the currentIndex counter changes

  3. In the viewControllerBefore and viewControllerAfter methods, I initialize my view controller and increase or decrease currentIndex when scrolling forward or backward

  4. After that, the didSet in the view controller works for me and the update takes place.

  5. But, in the end, instead of 8 controllers, I only see 2.

PageViewController

class PageViewController: UIViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {

let viewModel: GeneralViewModel

let locationViewModel: LocationViewModel

let realm = try! Realm()

var pageControl = UIPageControl.appearance()

var pageController: UIPageViewController!

var controllers = [UIViewController]()

var pendingIndex = 0

init(viewModel: GeneralViewModel, locationViewModel: LocationViewModel) {
    self.viewModel = viewModel
    self.locationViewModel = locationViewModel
    super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
    super.viewDidLoad()
    
    pageController = UIPageViewController(transitionStyle: .scroll,
                                                  navigationOrientation: .horizontal,
                                                  options: nil)
    pageController.delegate = self
    pageController.dataSource = self
    
    
    
    addChild(pageController)
    view.addSubview(pageController.view)
    
    let views = ["pageController": pageController.view] as [String: AnyObject]
            view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[pageController]|", options: [], metrics: nil, views: views))
            view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[pageController]|", options: [], metrics: nil, views: views))
    
    for _ in realm.objects(Cities.self) {

        let mainScreenViewController = MainScrenenViewController(viewModel: self.viewModel, locationViewModel: self.locationViewModel)
        
        self.controllers.append(mainScreenViewController)
    }
    
    pageController.setViewControllers([controllers[0]], direction: .forward, animated: false)
    
    setupPageControl()

}

func setupPageControl() {
    
    let realmCities = realm.objects(Cities.self)
    
    pageControl = UIPageControl(frame: CGRect(x: 0,y: 100,width: UIScreen.main.bounds.width,height: 50))
    pageControl.numberOfPages = realmCities.count
    pageControl.tintColor = UIColor.lightGray
    pageControl.pageIndicatorTintColor = UIColor.lightGray
    pageControl.currentPageIndicatorTintColor = UIColor.black
    pageControl.backgroundColor = UIColor.clear
    view.addSubview(pageControl)
   
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {

        if let index = controllers.firstIndex(of: viewController) {
            if index > 0 {
                let mainScreenViewController = MainScrenenViewController(viewModel: self.viewModel, locationViewModel: self.locationViewModel)
                
                mainScreenViewController.currentIndex -= 1
                
                controllers.append(mainScreenViewController)
                
                return controllers[index - 1]
            } else {
                return nil
            }
        }
    return nil
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        if let index = controllers.firstIndex(of: viewController) {
            if index < controllers.count - 1 {
             
            let mainScreenViewController = MainScrenenViewController(viewModel: self.viewModel, locationViewModel: self.locationViewModel)
                
            mainScreenViewController.currentIndex += 1
                
            controllers.append(mainScreenViewController)
                
            return controllers[index + 1]
            } else {
                return nil
            }
        }
        return nil
}

MainScreenViewController

class MainScrenenViewController: UIViewController, ChangeWeatherDelegate {

let viewModel: GeneralViewModel

let locationViewModel: LocationViewModel

var currentIndex = 0 {
    didSet {
        mainCollectionView.reloadData()
        todayCollectionView.reloadData()
        weekCollectionView.reloadData()
    }
}

//MARK: -Realm
let realm = try! Realm()

Solution

  • In viewDidLoad() in PageViewController, you are doing this:

    for _ in realm.objects(Cities.self) {
    
        let mainScreenViewController = MainScrenenViewController(viewModel: self.viewModel, locationViewModel: self.locationViewModel)
        
        self.controllers.append(mainScreenViewController)
    }
    

    so, you've created an array of 8 MainScreenViewController objects.

    However, you haven't set .currentIndex on them, so they currently are all currentIndex = 0.

    Then, in viewControllerBefore and viewControllerAfter, instead of getting the already created view controller from your controllers array, you are *creating another instance of MainScreenViewController and setting its .currentIndex to either -= 1 or += 1 ... but then you're appending it to controllers.

    Your code then returns a controller at index - 1 or index + 1 from the controllers array.

    It may help if you start a bit simpler... get your UIPageViewController working... and then add in the code for your view and location models.

    Here's a quick example - based on your code - that adds a centered label. showing the "index" of each page:

    class MainScrenenViewController: UIViewController {
        
        var currentIndex: Int = 0
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.backgroundColor = .yellow
            
            let label = UILabel()
            label.text = "\(currentIndex)"
            label.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(label)
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        }
    }
    
    class PageViewController: UIViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
        
        var pageControl = UIPageControl.appearance()
        
        var pageController: UIPageViewController!
        
        var controllers = [UIViewController]()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            pageController = UIPageViewController(transitionStyle: .scroll,
                                                  navigationOrientation: .horizontal,
                                                  options: nil)
            pageController.delegate = self
            pageController.dataSource = self
            
            addChild(pageController)
            view.addSubview(pageController.view)
            pageController.didMove(toParent: self)
    
            let views = ["pageController": pageController.view] as [String: AnyObject]
            view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[pageController]|", options: [], metrics: nil, views: views))
            view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[pageController]|", options: [], metrics: nil, views: views))
            
            for i in 0..<8 {
                
                let mainScreenViewController = MainScrenenViewController()
                mainScreenViewController.currentIndex = i
                self.controllers.append(mainScreenViewController)
            }
            
            pageController.setViewControllers([controllers[0]], direction: .forward, animated: false)
            
            setupPageControl()
        }
        
        func setupPageControl() {
            
            pageControl = UIPageControl(frame: CGRect(x: 0,y: 100,width: UIScreen.main.bounds.width,height: 50))
            pageControl.numberOfPages = self.controllers.count
            pageControl.tintColor = UIColor.lightGray
            pageControl.pageIndicatorTintColor = UIColor.lightGray
            pageControl.currentPageIndicatorTintColor = UIColor.black
            pageControl.backgroundColor = UIColor.clear
            view.addSubview(pageControl)
            
        }
        
        func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
            
            if let index = controllers.firstIndex(of: viewController) {
                if index > 0 {
    
                    return controllers[index - 1]
    
                } else {
                    return nil
                }
            }
            return nil
        }
        
        func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
            if let index = controllers.firstIndex(of: viewController) {
                if index < controllers.count - 1 {
                    
                    return controllers[index + 1]
    
                } else {
                    return nil
                }
            }
            return nil
        }
    
    }