Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - Call self.navigationController into custom cell class

Swift:

I have UICollectionViewController with another file/class UICollectionViewCell

The goal is to push UIViewController from my custom cell class.

something like this:

self.navigationController?.pushViewController(vc, animated: true)

I have no problems to implement push from didSelectItemAtIndexPath in UICollectionViewController but i want to do this from custom cell class registered into my UICollectionViewController.

When i try to push view from custom cell class unfortunately i don't have access self.navigationController

Also i want to do this 100% programmatically. I don't use Storyboard or Nib files

Thanks in advance.

like image 555
Oleg Popov Avatar asked Aug 12 '15 05:08

Oleg Popov


2 Answers

This is a bad idea. Views should not have/do that kind of logic. You should leave it with the Controller (that's what the MVC-Pattern is about).

Anyway:

class MyCollectionViewCell: UITableViewCell {
    var myViewController: MyViewController!
}

and when the cell is dequeued you could set it like this:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
    let cell: MyCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(myCellIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell
    let nvc: UINavigationController = UIStoryboard(name: "myStoryboard", bundle: nil).instantiateViewControllerWithIdentifier("myNavigationController") as! UINavigationController
    cell.myViewController = nvc.childViewControllers.first as! MyViewController

    return cell
}

and on selection:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
    let cell: MyCollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCollectionViewCell

    // I don't know where vc comes from
    cell.myViewController.navigationController?.pushViewController(vc, animated: true)
}

Still, there is no case I can think of, where this would make any sense. So rethink your architecture again.

Visualize the communication of your entities, by drawing it on a paper. You'll have to draw Models, Views and Controllers and only Controllers are allowed to "talk" to other Controllers.

Look at this and this

like image 184
ezcoding Avatar answered Nov 12 '22 06:11

ezcoding


I've recently came up with this question as well, and I have a way to demonstrate Akhilrajtr comment, as it might help others as well.

First in your cell class you need a protocol in top of the file:

protocol YourCellDelegate: NSObjectProtocol{
    func didPressCell(sender: Any)
}

Then in you cell class variables add this:

var delegate:YourCellDelegate!

When you are performing some action within your cell, trigger the function of your protocol:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
    delegate.didPressCell(sender: indexPath)
}

On your super main controller, you should conform to the delegate you've created:

class MyViewController: UIViewController, YourCellDelegate{...}

And, implement the function of the protocol, which will be triggered when the cell is pressed, just like you defined it before:

func didPressCell(sender: Any){
    let vc = SomeViewController()
    self.navigationController?.pushViewController(vc, animated: true)
}

Of course not to forget to give the reference for your delegate in the cell instantiation part in cellForItem function:

cell.delegate = self
like image 38
Itai Spector Avatar answered Nov 12 '22 05:11

Itai Spector