0

I try to show a ViewController when a button in a collectionViewCell is clicked.

I have in a dynamic tableView, a dynamic collectionView in one of tableViewCells.

In every collectionViewCells, there is a button which should be the trigger for the segue, to show the other View Controller

I tried with the following code, but the app crash :

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<Okm.bienController: 0x7fc8b0cfb1a0>) has no segue with identifier 'extend''

The segue identifier in my storyBoard is 'extend'.

 class photoCell: UITableViewCell, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource {
    ...

    func extendFunc(sender : UIButton) {

       bienController().performSegueWithIdentifier("extend", sender: sender.tag)
    }
}


class bienController : UIViewController, UITableViewDelegate, UITableViewDataSource {

...

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "extend" {
            let backItem = UIBarButtonItem()
            backItem.title = ""
            navigationItem.backBarButtonItem = backItem

            let extendView = segue.destinationViewController as! extendController
            extendView.image = image[sender]

        }
    }
}

enter image description here

Then, I tried this :

 func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            self.segue()
          // self.performSegueWithIdentifier("image", sender: nil)

    }

    func clickExtend(sender:Int){
        print(sender) //print the correct tag!
       self.segue()
    }

    func segue(){
         self.performSegueWithIdentifier("image", sender: nil)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        if segue.identifier == "image" {
            let backItem = UIBarButtonItem()
            backItem.title = ""
            navigationItem.backBarButtonItem = backItem
           // print(sender)

           let extendView = segue.destinationViewController as! extendController
           extendView.image = UIImage(named: "maison")

        }
    }
}

I linked the function clickExtend() with the button of my collectionCell. The segue works when it comes from didSelectRowAtIndexPath, but when I click on the button extend it crashes with the same error : 'Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'image'''

( I changed the segue identifier for 'image')

Then I try directly to show the view Controller without performing with Segue.

class photoCategoryCell: UITableViewCell, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource {

... 
    func extendFunc(sender : UIButton) {
        print(sender.tag)
        bienController().boo(sender.tag)
    }
}

And :

class bienController : UIViewController, UITableViewDelegate, UITableViewDataSource {

...

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
              self.boo(indexPath.row)

    }

func boo(sender:Int){
        let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let vc:UIViewController = storyboard.instantiateViewControllerWithIdentifier("extend") as! extendController
        let backItem = UIBarButtonItem()
        backItem.title = ""
        navigationItem.backBarButtonItem = backItem

        self.showViewController(vc as UIViewController, sender: nil)
    }
}

When I click on a tableViewCell it shows the View Controller, but when I click on the button "extend" in the collectionViewCell, nothing happends..

PLEASE, I NEED HELP!!

Thank you!!

FULL CODE

import UIKit

class photoCategoryCell: UITableViewCell, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var collectionView : UICollectionView!

    var hid = [true, true, true, true, true, true] //supp

    var imageList = [UIImage]()

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return 10
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("photoCell", forIndexPath: indexPath) as! photoCollectionViewCell

        cell.photoView.image = self.imageList[indexPath.row]
        cell.photoView.contentMode = .ScaleAspectFill
        cell.extend.hidden = true
        cell.blurView.hidden = true

        cell.extend.tag = indexPath.row
        cell.extend.addTarget(self, action: #selector(photoCategoryCell.extendFunc(_:)), forControlEvents: .TouchUpInside)
        return cell
    }

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        if let cell : photoCollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath) as! photoCollectionViewCell!
        {
            if cell.blurView.hidden == true {
            cell.blurView.hidden = false
            cell.extend.hidden = false
        } else {
            cell.blurView.hidden = true
            cell.extend.hidden = true
        }
        }
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {

        let cellWidth = (UIScreen.mainScreen().bounds.width) / 2
        return CGSize(width: cellWidth, height: cellWidth)

    }

    func extendFunc(sender : UIButton) {
        print(sender.tag)
        bienController().boo(sender.tag)
    }
}

import UIKit

class bienController : UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView : UITableView!
    @IBOutlet weak var tableViewTwo : UITableView!
    @IBOutlet weak var tableHeight : NSLayoutConstraint!
    @IBOutlet weak var viewBlack : UIView!
    let onglet = ["One", "Two", "Three", "Four", "Five"]


    var imageNb : Int = 3


    override func viewDidLoad() {
        super.viewDidLoad()
//        let gradient: CAGradientLayer = CAGradientLayer()
//        gradient.frame = self.viewBlack!.bounds
//        gradient.colors = [UIColor.clearColor().CGColor, UIColor(red: 225/255, green: 225/255, blue: 225/255, alpha: 0.5).CGColor]
//      
//        self.viewBlack.layer.insertSublayer(gradient, atIndex: 0)

        self.tableView?.tableFooterView = UIView(frame: CGRectZero)
        self.tableViewTwo?.tableFooterView = UIView(frame: CGRectZero)
        self.tableHeight?.constant = 38*5 
        self.tableViewTwo?.scrollEnabled = false

    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(true)
        UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.Default
        if let navigationBar = navigationController?.navigationBar {
            navigationBar.barTintColor = UIColor.whiteColor()
            navigationBar.translucent = false
            if let font = UIFont(name: "HelveticaNeue-Light", size: 20.0) {
                let navBarAttributesDictionary : [String : AnyObject]? = [
                    NSForegroundColorAttributeName: UIColor(red: 235/255, green: 67/255, blue: 27/255, alpha: 1.0),
                    NSFontAttributeName: font
                ]
                navigationBar.titleTextAttributes = navBarAttributesDictionary
                UIBarButtonItem.appearance().setTitleTextAttributes(navBarAttributesDictionary, forState: .Normal)
            }
        }


        let editButton = UIBarButtonItem(title: "Modifier", style: .Plain, target: self, action: #selector(bienController.modifier))

        self.navigationItem.rightBarButtonItem = editButton

    }

    func modifier(){

      //do something  
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == self.tableView {

            return 3

        } else {

            return 5
        }
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        if tableView == self.tableView {

            if indexPath.row == 0 {

                var cell = tableView.dequeueReusableCellWithIdentifier("oneCell") as! listCommandeCellTwo!

                if cell == nil {

                    cell = listCommandeCellTwo(style: UITableViewCellStyle.Default, reuseIdentifier: "oneCell")
                }

                cell.descriptionLabel.text = "description"
                cell.titre.text = "titre"

                return cell

            } else if indexPath.row == 1 && self.imageNb < 3 {

                var cell = tableView.dequeueReusableCellWithIdentifier("bienImgCell") as! bienImgCell!

                if cell == nil {

                    cell = bienImgCell(style: UITableViewCellStyle.Default, reuseIdentifier: "bienImgCell")
                }

                cell.imageOne.image = UIImage(named: "maison")
                cell.imageTwo.image = UIImage(named: "maison")
                cell.imageOne.contentMode = .ScaleAspectFill
                cell.imageTwo.contentMode = .ScaleAspectFill


                return cell

            } else if indexPath.row == 1 && self.imageNb >= 3 {

                var cell = tableView.dequeueReusableCellWithIdentifier("photoCategoryCell") as! photoCategoryCell!

                if cell == nil {

                    cell = photoCategoryCell(style: UITableViewCellStyle.Default, reuseIdentifier: "photoCategoryCell")
                }

                cell.imageList.removeAll(keepCapacity: false)
                for i in 0...10 {
                cell.imageList.append(UIImage(named: "maison")!)
                }


                cell.collectionView.delegate = cell
                cell.collectionView.dataSource = cell

                return cell

            } else {
                var cell = tableView.dequeueReusableCellWithIdentifier("bienCellOne") as! bienCellOne!

                if cell == nil {

                    cell = bienCellOne(style: UITableViewCellStyle.Default, reuseIdentifier: "bienCellOne")
                }


                cell.commentaire.delegate = cell
                cell.commentaire.editable = false
                cell.commentaire.setContentOffset(CGPointZero, animated: false)

                cell.commentaire.text = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."

                return cell
            }
        } else {


            var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! bienCellTwo!

            if cell == nil {

                cell = bienCellTwo(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
            }


            cell.titre.text = self.onglet[indexPath.row]
            cell.imageCategory.image = UIImage(named: "validate")
            cell.imageCategory.contentMode = .ScaleAspectFit

            if indexPath.row == 0 {
                cell.backgroundColor = UIColor(red: 235/255, green: 67/255, blue: 27/255, alpha: 1.0)
                cell.tintColor = UIColor.whiteColor()
                cell.titre.textColor = UIColor.whiteColor()
                let checkImage = UIImage(named: "chevron")
                let checkmark = UIImageView(image: checkImage)
                cell.accessoryView = checkmark
                cell.addBottomBorderWithColor(UIColor(red: 235/255, green: 67/255, blue: 27/255, alpha: 1.0), width: 1.0)
            } else {
                cell.addBottomBorderWithColor(UIColor(red: 225/255, green: 225/255, blue: 225/255, alpha: 1.0), width: 1.0)
                cell.backgroundColor = UIColor.whiteColor()
                cell.titre.textColor = UIColor(red: 235/255, green: 67/255, blue: 27/255, alpha: 1.0)
                let checkImage = UIImage(named: "chevron-orange")
                let checkmark = UIImageView(image: checkImage)
                cell.accessoryView = checkmark

            }
            return cell
        }

    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        //if tableView == self.tableViewTwo {

            print(indexPath.row)
            self.boo(indexPath.row)
           // self.segue()
          // self.performSegueWithIdentifier("image", sender: nil)
        //}
    }

    func boo(sender:Int){
        print(sender)
        let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let vc:UIViewController = storyboard.instantiateViewControllerWithIdentifier("extend") as! extendController
        let backItem = UIBarButtonItem()
        backItem.title = ""
        navigationItem.backBarButtonItem = backItem

        self.showViewController(vc as UIViewController, sender: nil)

       //self.segue()
    }

    func segue(){
       //  self.performSegueWithIdentifier("image", sender: nil)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        if segue.identifier == "image" {
            let backItem = UIBarButtonItem()
            backItem.title = ""
            navigationItem.backBarButtonItem = backItem

           let extendView = segue.destinationViewController as! extendController
           extendView.image = UIImage(named: "maison")

        }
    }
}
L.Vl
  • 113
  • 2
  • 14

1 Answers1

2

In the first case, the problem is this line:

bienController().performSegueWithIdentifier("extend", sender: sender.tag)

creates a new instance of the bienController class using the standard init method. As a result it has no knowledge of the storyboard and consequently cannot find the segue.

The second case is harder to pin down (you don't show how the clickExtend method is called from the button in the collectionViewCell), but I suspect it has the same problem.

In the final case, you are again creating a new instance of bienController. Because you now use showViewController, there is no problem with the lack of segue - so no error - but the new instance is not on screen, so showViewController does nothing (at least, it doesn't display anything on screen).

You need your collection view cell to have a reference to the existing instance of the bienViewController. I would need to see more of your setup to show exactly how to do this, but meanwhile you should check this question and the answers.

In this case, you need your photoCategoryCell to be able to call a method on your existing bienController view controller. In the photoCategoryCell, define a protocol which indicates the method it expects to call:

protocol PhotoCategoryCellDelegateProtocol {
    func didTapExtendInPhotoCollectionViewCellWithIndex(index: Int, inPhotoCategoryCell: photoCategoryCell)
}

Then add a delegate property to the photoCategoryCell with this type:

var delegate : PhotoCategoryCellDelegateProtocol?

And in the extendFunc method, replace bienController().boo(sender.tag) with the call:

self.delegate?.didTapExtendInPhotoCollectionViewCellWithIndex(sender.tag, inPhotoCategoryCell: self)

In the bienController class, implement this new function:

func didTapExtendInPhotoCollectionViewCellWithIndex(index: Int, inPhotoCategoryCell: photoCategoryCell) {
    self.boo(index) // or use performSegue if you prefer
}

Amend the class definition for bienController to indicate that it adopts this protocol:

class bienController : UIViewController, UITableViewDelegate, UITableViewDataSource, PhotoCategoryCellDelegateProtocol { ...

In the cellForRowAtIndexPath, be sure to set the delegate property on the photoCategoryCell to self:

        ...
        } else if indexPath.row == 1 && self.imageNb >= 3 {

            var cell = tableView.dequeueReusableCellWithIdentifier("photoCategoryCell") as! photoCategoryCell!

            if cell == nil {

                cell = photoCategoryCell(style: UITableViewCellStyle.Default, reuseIdentifier: "photoCategoryCell")
            }

            cell.imageList.removeAll(keepCapacity: false)
            for i in 0...10 {
            cell.imageList.append(UIImage(named: "maison")!)
            }
            // set the cell's delegate...
            cell.delegate = self
            cell.collectionView.delegate = cell
            cell.collectionView.dataSource = cell

            return cell
        } else ...

Note that I have defined the protocol method to pass both the collection view cell index and the table view cell: so if you have multiple table view rows with collection views, you can determine the correct TV row.

As a final style note, it is established practice for class names to begin with upper case letters; I would get into that habit now, so amend bienController to BienController, etc.

Community
  • 1
  • 1
pbasdf
  • 21,386
  • 4
  • 43
  • 75
  • Thank you @pbasdf! I thought something was wrong with this : bienController().performSegueWithIdentifier("extend", sender: sender.tag), I was right.. But I don't know how I can call properly a function from another view controller actually. I added my full code, How can I call a function of bienController from photoCategoryCell to perform Segue ? Thank you a lot! I hope this bug could be fixed!!! – L.Vl May 16 '16 at 05:11
  • Hi @pbasdf ! I can't thank you enough! It was a great lesson! Thank you, now the delegate makes much more sense for me! And thanks for the advise on the class names! – L.Vl May 17 '16 at 03:59