12

I've created custom tableView Controller, inside the cell i've placed a button to open the device photo library. My problem, i cant able to open imagePickerController from CustomCell.m, its shows below error. enter image description here

Please give some idea to fix my issue.

Ramdhas
  • 1,765
  • 1
  • 18
  • 26

7 Answers7

32

TableViewCell is a view, you can not present on views instead UIViewController can handle it. You should transfer the control from your cell to your controller that holds tableview and creates custom cell for it.

Try like this:

Custom Cell .h Class:

@protocol changePictureProtocol <NSObject>
-(void)loadNewScreen:(UIViewController *)controller;
@end

@property (nonatomic, retain) id<changePictureProtocol> delegate;

Then Synthesize it in.m.

Add this in m file:

-(IBAction)changePicture:(id)sender
{
    // ..... blah blah
    [self.delegate loadNewScreen:picker];
}

The viewcontroller that loads this cell:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   // create cell here

   cell.delegate = self;
}

-(void)loadNewScreen:(UIViewController *)controller;
{
  [self presentViewController:controller animated:YES completion:nil];
}

Its a psuedocode to give you an idea.

EDIT:

Swift equivalent:

CustomTableViewCell.swift code:

protocol ChangePictureProtocol : NSObjectProtocol { 
    func loadNewScreen(controller: UIViewController) -> Void;  
}

class CustomTableViewCell: UITableViewCell {

    // Rest of the class stuff

    weak var delegate: ChangePictureProtocol?

    @IBAction func changePicture(sender: AnyObject)->Void
    {
        var pickerVC = UIImagePickerController();
        if((delegate?.respondsToSelector("loadNewScreen:")) != nil)
        {
           delegate?.loadNewScreen(pickerVC);
        }  
    }
}

ViewController.swift code:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    var cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier") as CustomTableViewCell!

    cell.delegate = self;

    return cell;
}

func loadNewScreen(controller: UIViewController) {
    self.presentViewController(controller, animated: true) { () -> Void in

    };
}
NeverHopeless
  • 11,077
  • 4
  • 35
  • 56
  • Hey, would you mind explaining this in Swift? Having trouble converting it from objc from your explanation. Thanks a lot. – Lukesivi Nov 14 '15 at 16:27
  • @lukesIvi, check my edits for swift equivalent and let me know if you have any difficulty. – NeverHopeless Nov 18 '15 at 20:27
  • swift is not work for me, i tried to show print(delegate) but it only "nil" here is my code: func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { print("Hello outside") print(delegate) if((delegate?.respondsToSelector("loadNewScreen:")) != nil) { print("Hello insinde") let details = MovieDetail(); delegate?.loadNewScreen(details); print(delegate) } } – Evan Ngo Apr 09 '16 at 08:39
  • @EvanNgo, sorry for late response, just saw your message. Did you set the delegate ? `cell.delegate = self` ? – NeverHopeless Jul 06 '16 at 07:27
  • @NeverHopeless Could you give me a hand? I understand it but can't seem to execute it – luke Jul 24 '16 at 12:03
  • Actually I got it working with a little tweaking, thanks. – luke Jul 24 '16 at 12:21
  • Thanks a lot ! You make my day. The world of programming is ugly and beautiful at the same time xD – kxko Nov 28 '17 at 21:20
  • Great Work Thank you for your detail answer with explanation. – Mihir Oza Mar 23 '18 at 07:40
  • when using the IBAction what should you put for Sender? – Junaid Mar 03 '21 at 19:09
  • @Junaid, not sure if i understood your question fully, perhaps this might be something you are looking for: https://stackoverflow.com/questions/5578139/objective-c-what-is-a-id-sender – NeverHopeless Mar 04 '21 at 14:57
11

The answers proposing a delegate or instance variable are correct, but, however, in most cases it is not important to use a special view controller to present the new controller. In these cases the following solution is much simpler: Just use the applications root view controller:

UIViewController* activeVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[activeVC presentViewController:'new view controller'
                       animated:YES
                     completion:NULL];
LaborEtArs
  • 1,938
  • 23
  • 27
  • 2
    this won't always work with if you structure the table view and cell as not being in the root view controller heirarchy "Warning: Attempt to present on whose view is not in the window hierarchy! – greenhouse Apr 06 '16 at 05:57
1

presentViewController: message is there for Viewcontroller. Do delegate the control from Cell to viewController and use the same line would solve your problem. UITableViewCell does not responds to presentViewController: message.

Rajesh
  • 10,318
  • 16
  • 44
  • 64
1

You need a UIViewController to present from. There are a few things you can do here. One would be to create a custom delegate protocol with a changePicturePressed callback method. Then you can assign the containing view controller as that delegate and perform the presentation in the delegate method.

The other thing you can do is pass the UIViewController into your cell during initialization and set it as a weak property. Then you can perform the presentation directly from inside the cell using that property.

Dima
  • 23,484
  • 6
  • 56
  • 83
1

Make IBOutlet of your button

Then in cellForRowAtIndexPath give target to the button

CustomCell *customCell=[tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
[customCell.yourButton addTarget:self action:@selector(yourButtonAction:) forControlEvents:UIControlEventTouchUpInside];
Jay Gajjar
  • 2,661
  • 2
  • 21
  • 35
1

One other way to do this is pass reference of the controller of the CustomCell to the CustomCell and use that to present the new controller.

Swift:

CustomCell.swift :

class CustomTableViewCell: UITableViewCell {

    // Rest of the class stuff

    var parentViewController: UIViewController? = nil

    gotoNewControllerBtn.addTarget(self, action: #selector(gotoNewController), for: .touchUpInside)

    func gotoNewController() {
        let newViewController = NewViewController()
        parentViewController.present(newViewController, animated: true, completion: nil)
    }
}

ViewController.swift:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    var cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier") as CustomTableViewCell!

    cell.parentViewController = self;

    return cell;
}
crc442
  • 607
  • 7
  • 13
-1

You need viewcontroller for presenting the view. You cannot present viewcontroller on tableviewcells.

Tendulkar
  • 5,550
  • 2
  • 27
  • 53