I am working on an iOS application which interacts with an API using alamofire and swiftyJSON. In this api I get a bunch of values returned and one of them is images. the Images returned comes in form of an array but i am able to iterate through the array and display a single image. To make the application more advanced, I decided to implement UIPageViewController class in my application. I called the API function and tried to pass my images into view controllers.
List of things in my storyboard
I have my codes fine to the best of my knowledge but when I run the application nothing happens on in the console. Below is my codes.
protocol ProductImagesPageViewControllerDelegate: class {
func setupPageController(numberOfPages: Int)
func turnPageController(to index: Int)
}
class ProductPageVC: UIPageViewController {
weak var pageViewControllerDelegate: ProductImagesPageViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
automaticallyAdjustsScrollViewInsets = false
dataSource = self
delegate = self
}
func configureImg() {
let productId = ProductServices.instance.selectedProduct?.id
ProductServices.instance.findIndividualProducts(id: productId!, completion: { (success) in
if success {
ProductServices.instance.productDetails.forEach({ (productDetail) in
let images = productDetail.productImg.count
if images > 0 {
for image in 0..<(images) {
let imageVC = self.storyboard?.instantiateViewController(withIdentifier: PRODUCT_IMAGE_VC)
self.controllers.append(imageVC!)
}
}
})
}
})
}
lazy var controllers: [UIViewController] = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var controllers = [UIViewController]()
let productId = ProductServices.instance.selectedProduct?.id
ProductServices.instance.findIndividualProducts(id: productId!, completion: { (success) in
if success {
ProductServices.instance.productDetails.forEach({ (productDetail) in
let images = productDetail.productImg.count
if images > 0 {
for image in 0..<(images) {
let imageVC = storyboard.instantiateViewController(withIdentifier: PRODUCT_IMAGE_VC)
controllers.append(imageVC)
}
}
})
}
})
self.pageViewControllerDelegate?.setupPageController(numberOfPages: controllers.count)
return controllers
}()
func turnToPage(index: Int)
{
let controller = controllers[index]
var direction = UIPageViewControllerNavigationDirection.forward
if let currentVC = viewControllers?.first {
let currentIndex = controllers.index(of: currentVC)!
if currentIndex > index {
direction = .reverse
}
}
self.configureDisplaying(viewController: controller)
setViewControllers([controller], direction: direction, animated: true, completion: nil)
}
func configureDisplaying(viewController: UIViewController)
{
for (index, vc) in controllers.enumerated() {
if viewController === vc {
if let imageVC = viewController as? ImagesVC {
imageVC.configureImage(productIndex: index)
self.pageViewControllerDelegate?.turnPageController(to: index)
}
}
}
}
}
// MARK: - UIPageViewControllerDataSource
extension ProductPageVC : UIPageViewControllerDataSource
{
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
{
if let index = controllers.index(of: viewController) {
if index > 0 {
return controllers[index-1]
}
}
return controllers.last
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if let index = controllers.index(of: viewController) {
if index < controllers.count - 1 {
return controllers[index + 1]
}
}
return controllers.first
}
}
extension ProductPageVC : UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController])
{
self.configureDisplaying(viewController: pendingViewControllers.first as! ImagesVC)
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
{
if !completed {
self.configureDisplaying(viewController: previousViewControllers.first as! ImagesVC)
}
}
}
This is my ImageVC code
class ImagesVC: UIViewController {
@IBOutlet weak var imageView: UIImageView!
func configureImage(productIndex : Int) -> Void {
ProductServices.instance.productDetails.forEach { (productImg) in
if productImg.productImg.count > 0 {
imageView.sd_setImage(with: URL(string: productImg.productImg[productIndex]!) )
} else {
imageView.image = UIImage(named: "image_not_found")
}
}
}}
This is my HeaderImageView code
class HeaderImageVC: UIView {
@IBOutlet weak var pageControl: UIPageControl!
}
extension HeaderImageVC : ProductImagesPageViewControllerDelegate {
func setupPageController(numberOfPages: Int)
{
pageControl.numberOfPages = numberOfPages
}
func turnPageController(to index: Int)
{
pageControl.currentPage = index
}
}
I have no idea why the code is not working but further codes would be supplied on request. Thanks.
According to suggestion
var images = (ProductServices.instance.productDetails.first?.productImg)
lazy var controllers: [UIViewController] = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var controllers = [UIViewController]()
if let images = self.images {
for image in images {
let imageVC = storyboard.instantiateViewController(withIdentifier: PRODUCT_IMAGE_VC)
controllers.append(imageVC)
}
}
self.pageViewControllerDelegate?.setupPageController(numberOfPages: controllers.count)
return controllers
}()
this still returns empty
problem
lazy var controllers: [UIViewController] = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var controllers = [UIViewController]()
// IT WILL NOT WAIT TO FINISH IT
let productId = ProductServices.instance.selectedProduct?.id
ProductServices.instance.findIndividualProducts(id: productId!, completion: { (success) in
if success {
ProductServices.instance.productDetails.forEach({ (productDetail) in
// NO USE OF productDetail as it is already returned
let images = productDetail.productImg.count
if images > 0 {
for image in 0..<(images) {
let imageVC = storyboard.instantiateViewController(withIdentifier: PRODUCT_IMAGE_VC)
controllers.append(imageVC)
}
}
})
}
})
// controllers.count is 0
self.pageViewControllerDelegate?.setupPageController(numberOfPages: controllers.count)
return controllers
}()
if you observe above code and you should debug it, then you will find that controllers
is empty Because it is async task and compiler will not wait for finish findIndividualProducts
task to complete it will return the empty array which you have define so outcome is your controller has nothing to show !! -> Make sense
Solution is that simple you can create method that will set the call the API findIndividualProducts
and assign it to the controllers
now the controller is simple plain property.
Hope it is helpful
EDIT
First create one method and call it from view did load or view will appear whatever suits you
private func getAllControllers () {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var controllers = [UIViewController]()
// IT WILL NOT WAIT TO FINISH IT
let productId = ProductServices.instance.selectedProduct?.id
ProductServices.instance.findIndividualProducts(id: productId!, completion: { (success) in
if success {
ProductServices.instance.productDetails.forEach({ (productDetail) in
// NO USE OF productDetail as it is already returned
let images = productDetail.productImg.count
if images > 0 {
for image in 0..<(images) {
let imageVC = storyboard.instantiateViewController(withIdentifier: PRODUCT_IMAGE_VC)
controllers.append(imageVC)
}
self.pageViewControllerDelegate?.setupPageController(numberOfPages: controllers.count)
self.controllers = controllers
}
})
}
})
}
and remove lazy block from your controller property
var controllers: [UIViewController] = []
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With