title: Delete/remove displayed controller inside Page View Controller on clicking delete button, Swift
body: <p>I am displaying images in a collection view controller. When the cell is tapped, I am passing those images to page view controller, where the user is given an option to delete or add image description as you can see in the below images.</p>
  
  <p><a href="https://i.stack.imgur.com/yr4Lb.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yr4Lb.jpg" alt="enter image description here"></a></p>
  
  <p>When the user clicks delete button, I would the page (or view controller) to be deleted (just like the behaviour seen, when delete button is clicked in  in Apple iOS photos app). </p>
  
  <p>I tried to achieve it, by passing an array of empty view controller to pageViewController (See Code A), which resulted in a error 
  <code>The number of view controllers provided (0) doesn't match the number required (1) for the requested transition</code> which makes sense.</p>
  
  <p>Am I on the right track, if yes, how can I fix the issue ? 
  If not, Is there a better approach to achieve the same ?</p>
  
  <p>Code A: Taken from Code B</p>
  
  <p><code>pageVC.setViewControllers([], direction: .forward, animated: true, completion: nil)</code></p>
  
  <p>Code B: Taken from <code>UserPickedImageVC</code></p>
  
  <pre><code>func deleteCurrentImageObject(){
  
      guard let controllers = self.navigationController?.viewControllers else{
          return
      }
      for viewController in controllers {
          if viewController.className == "UserPickedImagesVC"{
  
              let vc              =   viewController as! UserPickedImagesVC
              let objectCount     =   vc.imageObjectsArray.count
  
              guard objectCount &gt; 0 &amp;&amp; objectCount &gt;= itemIndex else {
                  return
              }
  
              vc.imageObjectsArray.remove(at: itemIndex) //  Removing imageObject from the array
  
  
              if let pageVC = vc.childViewControllers[0] as? UIPageViewController {
                  pageVC.setViewControllers([], direction: .forward, animated: true, completion: nil)
  
              }
  
          }
      }
  } 
  </code></pre>
  
  <p><strong>Storyboard</strong></p>
  
  <p><a href="https://i.stack.imgur.com/kjThG.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/kjThG.jpg" alt="enter image description here"></a></p>
  
  <p>Here is the complete code (except some custom UICollectionViewCell):</p>
  
  <p><strong>UserPickedImagesCVC.swift</strong></p>
  
  <pre><code>import UIKit
  import ImagePicker
  import Lightbox
  
  private let imageCellId     =   "imageCell"
  private let addCellId       =   "addImagesCell"
  
  class UserPickedImagesCVC: UICollectionViewController, ImagePickerDelegate, UserPickedImagesVCProtocol {
  
      let imagePickerController = ImagePickerController()
      //var userPickedImages = [UIImage]()
      var userPickedImages = [ImageObject]()
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
          imagePickerController.delegate = self as ImagePickerDelegate
  
          // Uncomment the following line to preserve selection between presentations
          // self.clearsSelectionOnViewWillAppear = false
  
          // Register cell classes
          self.collectionView!.register(ImageCVCell .self, forCellWithReuseIdentifier: imageCellId)
          self.collectionView!.register(ImagePickerButtonCVCell.self, forCellWithReuseIdentifier: addCellId)
  
          // Do any additional setup after loading the view.
      }
  
      override func didReceiveMemoryWarning() {
          super.didReceiveMemoryWarning()
          // Dispose of any resources that can be recreated.
      }
  
      /*
      // MARK: - Navigation
  
      // In a storyboard-based application, you will often want to do a little preparation before navigation
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          // Get the new view controller using [segue destinationViewController].
          // Pass the selected object to the new view controller.
      }
      */
  
      // MARK: UICollectionViewDataSource
  
      override func numberOfSections(in collectionView: UICollectionView) -&gt; Int {
          // #warning Incomplete implementation, return the number of sections
          return 1
      }
  
  
      override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
          // #warning Incomplete implementation, return the number of items
          return userPickedImages.count + 1
      }
  
      override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {
          let item = indexPath.item
          print("item: \(item)")
          if item &lt; userPickedImages.count {
  
              let cell = collectionView.dequeueReusableCell(withReuseIdentifier: imageCellId, for: indexPath) as! ImageCVCell
              let userPickedImageObject = userPickedImages[item]
              //cell.showImagesButton.setImage(userPickedImage, for: .normal)
  
              cell.showImagesButton.setImage(userPickedImageObject.image, for: .normal)
              cell.showImagesButton.addTarget(self, action: #selector(showAlreadyPickedImages), for: .touchUpInside)
              //cell.addButton.addTarget(self, action: #selector(showAlreadyPickedImages), for: .touchUpInside)
  
              return cell
          }
  
          let cell = collectionView.dequeueReusableCell(withReuseIdentifier: addCellId, for: indexPath) as! ImagePickerButtonCVCell
          cell.addButton.addTarget(self, action: #selector(showImagePickerController), for: .touchUpInside)
          return cell
  
  
          // Configure the cell
      }
  
  
      //Function shows imagePicker that helps in picking images and capturing images with camera
      func showImagePickerController(){
          print("showImagePickerController func called")
          //self.present(imagePickerController, animated: true, completion: nil)
          self.navigationController?.pushViewController(imagePickerController, animated: true)
      }
  
  
      func showAlreadyPickedImages(){
          let vc = self.storyboard?.instantiateViewController(withIdentifier: "userPickedImagesVC") as! UserPickedImagesVC
          //vc.contentImages = userPickedImages
          vc.imageObjectsArray = userPickedImages
          vc.showingAlreadySavedImages = true
          self.navigationController?.pushViewController(vc, animated: true)
      }
  
      func setImagesInCells(imageObjects : [ImageObject]){
          print("setImagesInCells func called in CVC")
          userPickedImages += imageObjects
          collectionView?.reloadData()
      }
  
  
      // MARK: - ImagePickerDelegate
  
      func cancelButtonDidPress(_ imagePicker: ImagePickerController) {
          imagePicker.dismiss(animated: true, completion: nil)
      }
  
      func wrapperDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
          guard images.count &gt; 0 else { return }
  
          let lightboxImages = images.map {
              return LightboxImage(image: $0)
          }
  
          let lightbox = LightboxController(images: lightboxImages, startIndex: 0)
          imagePicker.present(lightbox, animated: true, completion: nil)
      }
  
      func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
          imagePicker.dismiss(animated: true, completion: nil)
  
          let vc = storyboard?.instantiateViewController(withIdentifier: "userPickedImagesVC") as! UserPickedImagesVC
  
          //vc.contentImages = images
          vc.imageObjectsArray =  convertImagesToImageObjects(images)
  
          //self.present(vc, animated: true, completion: nil)
          self.navigationController?.pushViewController(vc, animated: true)
      }
  
      func convertImagesToImageObjects(_ imagesArray : [UIImage]) -&gt; [ImageObject]{
          var imageObjects = [ImageObject]()
          for image in imagesArray{
              var imageObject = ImageObject()
              imageObject.image = image
              imageObject.imageDescription = ""
              imageObjects.append(imageObject)
          }
          return imageObjects
      }
  
  }
  </code></pre>
  
  <p><strong>UserPickedImagesVC.swift</strong></p>
  
  <pre><code>import UIKit
  
  protocol UserPickedImagesVCProtocol{
      func setImagesInCells(imageObjects : [ImageObject])
  }
  
  class ImageObject : NSObject{
      var imageDescription :  String?
      var image            :  UIImage?
  }
  
  
  class UserPickedImagesVC: UIViewController, UIPageViewControllerDataSource {
  
      var pageViewController  :   UIPageViewController?
      let placeholderText     =   "Image description.."
  
      var imageObjectsArray =   [ImageObject]()
      var delegate            :   UserPickedImagesVCProtocol!
      var showingAlreadySavedImages = false
  
  
  
      override func viewDidLoad() {
          super.viewDidLoad()
          edgesForExtendedLayout = [] // To avoid view going below nav bar
          //self.delegate = self.navigationController?.viewControllers
  
  
          // Do any additional setup after loading the view, typically from a nib.
          if showingAlreadySavedImages{
              navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneTapped))
          }else{
              navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save", style: .plain, target: self, action: #selector(saveTapped))
          }
          // createImageAndDescriptionDict()
          createPageViewController()
          setupPageControl()
      }
  
      override func didReceiveMemoryWarning() {
          super.didReceiveMemoryWarning()
          // Dispose of any resources that can be recreated.
      }
  
      func createPageViewController(){
          print("createPageViewController func called")
          let pageController = self.storyboard?.instantiateViewController(withIdentifier: "userPickedImagesPageController") as! UIPageViewController
  
          pageController.dataSource = self
  
          if imageObjectsArray.count &gt; 0 {
              let firstController = getItemController(0)
              let startingViewControllers = [firstController]
  
              pageController.setViewControllers(startingViewControllers as! [UIViewController], direction: .forward, animated: false, completion: nil)
  
          }
  
          pageViewController = pageController
          addChildViewController(pageViewController!)
          self.view.addSubview((pageViewController?.view)!)
          pageViewController?.didMove(toParentViewController: self)
      }
  
  
      // Creata the appearance of pagecontrol
      func setupPageControl(){
  
          let appearance = UIPageControl.appearance()
          appearance.pageIndicatorTintColor = UIColor.gray
          appearance.currentPageIndicatorTintColor = UIColor.white
          appearance.backgroundColor = UIColor.darkGray
  
      }
  
  
  
      //MARK: Delagate methods
      func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -&gt; UIViewController? {
          let itemController = viewController as! UserPickedImageVC
  
          if itemController.itemIndex &gt; 0 {
              return self.getItemController(itemController.itemIndex-1)
          }
          return nil
      }
  
  
      func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -&gt; UIViewController? {
          let itemController = viewController as! UserPickedImageVC
  
          if itemController.itemIndex + 1 &lt; imageObjectsArray.count{
  
              return getItemController(itemController.itemIndex+1)
  
          }
  
          return nil
      }
  
  
      func presentationCount(for pageViewController: UIPageViewController) -&gt; Int {
          return imageObjectsArray.count
      }
  
  
      func presentationIndex(for pageViewController: UIPageViewController) -&gt; Int {
          return 0
      }
  
  
      func currentControllerIndex() -&gt; Int{
          let pageItemController = self.currentControllerIndex()
  
          if let controller = pageItemController as? UserPickedImageVC{
              return controller.itemIndex
          }
  
          return -1
      }
  
  
      func currentController() -&gt; UIViewController?{
          if(self.pageViewController?.viewControllers?.count)! &gt; 0{
              return self.pageViewController?.viewControllers?[0]
          }
          return nil
      }
  
  
      func getItemController(_ itemIndex:Int) -&gt; UserPickedImageVC?{
  
          if itemIndex &lt; imageObjectsArray.count{
              let pageItemController = self.storyboard?.instantiateViewController(withIdentifier: "userPickedImageVC") as! UserPickedImageVC
  
              pageItemController.itemIndex = itemIndex
              //pageItemController.imageName = imageObjectsArray[itemIndex]
  
              //pageItemController.imageToShow = imageObjectsArray[itemIndex]
              //pageItemController.imageToShow = getImageFromImageDescriptionArray(itemIndex, imagesAndDescriptionArray)
              pageItemController.imageObject  =   imageObjectsArray[itemIndex]
              pageItemController.itemIndex    =   itemIndex
              pageItemController.showingAlreadySavedImage = showingAlreadySavedImages
              print("Image Name from VC: \(imageObjectsArray[itemIndex])")
              return pageItemController
          }
          return nil
      }
  
  
  
  
  
      // Passing images back to Collection View Controller when save button is tapped
  
      func saveTapped(){
  
          let viewControllers = self.navigationController?.viewControllers
          //print("viewControllers: \(viewControllers)")
  
          if let destinationVC = viewControllers?[0]{
              self.delegate = destinationVC as! UserPickedImagesVCProtocol
              //self.delegate.setImagesInCells(images : imageObjectsArray)
              self.delegate.setImagesInCells(imageObjects : imageObjectsArray)
              self.navigationController?.popToViewController(destinationVC, animated: true)
          }
  
      }
  
      func doneTapped(){
          let viewControllers = self.navigationController?.viewControllers
  
          if let destinationVC = viewControllers?[0] {
              self.navigationController?.popToViewController(destinationVC, animated: true)
          }
      }
  
  }
  </code></pre>
  
  <p><strong>UserPickedImageVC.swift</strong></p>
  
  <pre><code>    import UIKit
  import ImageScrollView
  
  extension UIViewController {
      var className: String {
          return NSStringFromClass(self.classForCoder).components(separatedBy: ".").last!;
      }
  }
  
  class UserPickedImageVC: UIViewController, UITextViewDelegate {
  
  
  
      var itemIndex : Int             = 0
      var imageDescription : String   = ""
      var imageScrollView = ImageScrollView()
      var imageDescriptionTextView : UITextView!
      var imageToShow : UIImage!
  
      var imageObject : ImageObject?        
      var deleteButton = UIButton(type: .system)
      var showingAlreadySavedImage = false
  
      var pageViewController : UIPageViewController!
  
  
  
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
  
          edgesForExtendedLayout = [] // To avoid images going below the navigation bars
  
          pageViewController = self.parent as! UIPageViewController
  
          setConstraints()
          setImageAndDescription()
  
      }
  
      override func didReceiveMemoryWarning() {
          super.didReceiveMemoryWarning()
          // Dispose of any resources that can be recreated.
      }
  
  
      //MARK: TextView delegate methods
      func textViewDidBeginEditing(_ textView: UITextView)
      {
          if (imageDescriptionTextView.text == "Image description..")
          {
              imageDescriptionTextView.text = ""
              imageDescriptionTextView.textColor = .black
          }
          imageDescriptionTextView.becomeFirstResponder() //Optional
      }
  
      func textViewDidEndEditing(_ textView: UITextView)
      {
          let imageDescription = imageDescriptionTextView.text
  
          if (imageDescription == "")
          {
              imageDescriptionTextView.text = "Image description.."
              imageDescriptionTextView.textColor = .lightGray
          }
          imageObject?.imageDescription = imageDescription
          updateImageObject(imageObject!)
          imageDescriptionTextView.resignFirstResponder()
      }
  
  
  
      //MARK: Private Methods
      func setImageAndDescription(){
  
          if let imageToDisplay = imageObject?.image{
              imageScrollView.display(image: imageToDisplay)  // Setting Image
          }
          imageDescriptionTextView.text = imageObject?.imageDescription    // Setting Description
  
      }
  
      // Function to update imageObject in UserPickedImagesVC
      func updateImageObject(_ imageObject: ImageObject){
          guard let controllers = self.navigationController?.viewControllers else{
              return
          }
          for viewController in controllers {
              if viewController.className == "UserPickedImagesVC" {
                  let vc = viewController as! UserPickedImagesVC
                  vc.imageObjectsArray[itemIndex] = imageObject
  
              }
          }
      }
  
  
      // Function to delete imageObject from UserPickedImagesVC
      func deleteCurrentImageObject(){
  
          guard let controllers = self.navigationController?.viewControllers else{
              return
          }
          for viewController in controllers {
              if viewController.className == "UserPickedImagesVC"{
  
                  let vc              =   viewController as! UserPickedImagesVC
                  let objectCount     =   vc.imageObjectsArray.count
  
                  guard objectCount &gt; 0 &amp;&amp; objectCount &gt;= itemIndex else {
                      return
                  }
  
                  vc.imageObjectsArray.remove(at: itemIndex) //  Removing imageObject from the array
  
  
                  if let pageVC = vc.childViewControllers[0] as? UIPageViewController {
                      pageVC.setViewControllers([], direction: .forward, animated: true, completion: nil)
  
                  }
  
              }
          }
      }
  
      func showOrHideDeleteButton(){
          if showingAlreadySavedImage{
              print("deleteButton.isNotHidden")
              deleteButton.isHidden   = false
          }else{
              print("deleteButton.isHidden")
              deleteButton.isHidden   = true
          }
      }
  
  
      func setConstraints(){
          let viewSize    =   self.view.frame.size
          let viewWidth   =   viewSize.width
          let viewHeight  =   viewSize.height
          print("viewWidth: \(viewWidth), viewHeight: \(viewHeight)")
  
          view.addSubview(imageScrollView)
          imageScrollView.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
          deleteButton.tintColor = Colors.iOSBlue
          deleteButton.setImage(#imageLiteral(resourceName: "delete"), for: .normal)
          deleteButton.backgroundColor = Colors.white
          deleteButton.layer.cornerRadius = 25
          deleteButton.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
  
          //deleteButton.currentImage.
          deleteButton.imageView?.tintColor = Colors.iOSBlue
          deleteButton.addTarget(self, action: #selector(deleteCurrentImageObject), for: .touchUpInside)
          deleteButton.translatesAutoresizingMaskIntoConstraints = false
          view.addSubview(deleteButton)
          showOrHideDeleteButton()
  
          imageDescriptionTextView = UITextView()
          imageDescriptionTextView.delegate = self as! UITextViewDelegate
          imageDescriptionTextView.text = "Image description.."
          imageDescriptionTextView.textColor = .lightGray
  
          //imageScrollView.clipsToBounds = true
  
          imageDescriptionTextView.translatesAutoresizingMaskIntoConstraints = false
          //imageDescriptionTextView.backgroundColor = UIColor.white.withAlphaComponent(0.8)
          imageDescriptionTextView.backgroundColor = UIColor.white
          imageDescriptionTextView.layer.cornerRadius = 5
          imageDescriptionTextView.layer.borderColor = UIColor.lightGray.cgColor
          imageDescriptionTextView.layer.borderWidth = 0.5
          view.addSubview(imageDescriptionTextView)
  
  
          let viewsDict = [
              "imageDescriptionTextView"  :   imageDescriptionTextView,
              "deleteButton"              :   deleteButton
              ] as [String:Any]
  
          view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-5-[imageDescriptionTextView]-70-|", options: [], metrics: nil, views: viewsDict))
          view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[imageDescriptionTextView(50)]-5-|", options: [], metrics: nil, views: viewsDict))
          imageDescriptionTextView.sizeThatFits(CGSize(width: imageDescriptionTextView.frame.size.width, height: imageDescriptionTextView.frame.size.height))
  
          view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[deleteButton(50)]-5-|", options: [], metrics: nil, views: viewsDict))
          view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[deleteButton(50)]-5-|", options: [], metrics: nil, views: viewsDict))
      }
  
  }
  </code></pre>