Search code examples
swiftfirebaseuipageviewcontroller

UIPageViewController + firebase


I'm using UIPageViewController to make book pages and the pages are images that will be fetched from the firebase. the problem is I got this error

(Cannot convert value of type 'books' to expected element type 'Array.ArrayLiteralElement' (aka 'UIViewController')

'books' is a struct I made for firebase


import Foundation
import Firebase

struct books {
    
    let bookId: String 
    let imageURL: String
}

extension booksC {
  init(_ dictionary: [String: Any]) {
    
    self.bookId = dictionary["bookId"] as? String ?? "no book id"
    self.imageURL = dictionary["imageURL"] as? String ?? "no image url"
  }
}

I'm using this code, what I understand is I can't use an array of images what I should use is an array of controllers and I don't know how to do that in this case. help is appreciated

import UIKit
import FirebaseFirestore


class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate  {

        let pageViewController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)


        private var pages  = [books]()
    
        private var listener: ListenerRegistration?

        override func viewDidLoad() {
            super.viewDidLoad()
            dataSource = self
            delegate = self

        // index

            guard  let pagesFirst = pages.last else { return }

            setViewControllers([pagesFirst], direction: .reverse, animated: true)
      
        //TODO: add listener


        }

        func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation {
            var location = SpineLocation.max
            if orientation == .landscapeLeft || orientation == .landscapeRight {
                self.pageViewController.isDoubleSided = true

                location = .mid
            }

            return location
        }

        func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
            let index = self.pages.firstIndex(where: {$0 == viewController}) ?? 0
            if index == 0 { return nil }
            return pages[index - 1]

        }

        func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
            let index = self.pages.firstIndex(where: {$0 == viewController}) ?? 0
            if index == pages.count - 1 { return nil }
            return pages[index + 1]
        }

    }

class ImageViewController: UIViewController {


    let imageView = UIImageView()
    init(image: UIImage) {
        imageView.image = image
        super.init(nibName: nil, bundle: nil)
    }



    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(imageView)
        imageView.fillSuperview()
        imageView.contentMode = .scaleAspectFit
        imageView.clipsToBounds = true
        imageView.backgroundColor = .white


    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    public func setupImage(for book: books){
    imageView.kf.setImage(with: URL(string: book.imageURL))
}

}


Solution

  • enter code hereyou are using your array private var pages = [books]() in setViewControllers which expect a UIViewController

    This is how setViewControllers is declared:

    func setViewControllers(_ viewControllers: [UIViewController]?, 
                  direction: UIPageViewController.NavigationDirection, 
                   animated: Bool, 
                 completion: ((Bool) -> Void)? = nil)
    

    Parameters


    viewControllers

    The view controller or view controllers to be displayed.

    direction

    The navigation direction.

    animated

    A Boolean value that indicates whether the transition is to be animated.

    I think you should create an instance of ImageViewController then set the image using setupImage(for book: books) (which you can access since is a public method and finally assign that view controller your the page controller:

    guard  let pagesFirst = pages.last else { return }
    let imageViewController = ImageViewController()
    imageViewController.setupImage(for book: pagesFirst)
    setViewControllers([imageViewController], direction: .reverse, animated: true)
    

    EDITED:

    Sorry, as far as the second error you get, it should be

     imageViewController.setupImage(for:pagesFirst)
    

    as for is the name available outside the class.

    For the first error, what init options does it give you. It should be correct.

    Try also to change your code declaring imageView this way :

    var imageView : UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false // required if you need to work with autolayout
        return imageView
    }()
    

    removing:

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

    lastly, you should name your struct book with a capital B.