1
votes

I have a UITableView whose delegate and data source is in a different file. When tapping a row, in tableView:didSelectRowAtIndexPath: a new view controller should be pushed on stack. Since the NSObject file (which contains the UITableView delegate and data source) doesn't have presentViewController:animated:completion: I can't push a new view controller.

I figured there are two ways to fix this.

Option 1:

Adding a property of the tableview's view controller (RootViewController) to the NSObject file and setting that property equal to the view controller when initializing the object. That way I could do this in tableView:didSelectRowAtIndexPath:

[self.rootVC presentViewController:detailVC animated:YES completion:nil];

Option 2:

I could also add a delegate to the NSObject file which does the logic of changing view controllers in RootViewController.

@protocol YBMatchesTableViewDelegateAndDataSourceDelegate
@optional

-(void)rowTapped;

@end

@property(nonatomic,assign)id delegate;

In tableView:didSelectRowAtIndexPath: [self.delegate rowTapped];. Finally, in RootViewController.

-(void)rowTapped {
    DetailViewController *detailVC = [[DetailViewController alloc] init];
    [self presentViewController:detailVC animated:YES completion:nil];
}

What doesn't work:

  • [[RootViewController new] presentViewController:detailVC animated:YES completion:nil];
  • Subclassing RootViewController and putting the tableview's delegate and data source in there.

Both say it is not in the view hierarchy. Warning: Attempt to present <DetailViewController 0x109123ff0> on <RootViewController: 0x10912aef0> whose view is not in the window hierarchy!

Which one would you prefer? Or which one should I absolutely not use? I incline to go for the delegate since the first one gets me another property/object.

1
Could you expand on option 2? I think that's probably the best option, but I want to be more clear how you intend to do that.nhgrif
How do you put your table view on the screen? Are you using a controller for that, i.e. a kind of UIViewController? That would be the object responsible for presenting the new view controller as well.blackbird
Nope, just create a UITableView programmatically.yoeriboven

1 Answers

1
votes

I would probably go with option 2. It means that your delegate and datasource doesn't need to hold a reference to a viewcontroller just so that it can present another viewcontroller. It's also an extra separation of responsibility - your delegate / datasource is only responsible for managing the tableview's data, not for performing UI functionality / navigation when the user selects something.

By implementing a delegate, your YBMatchesTableViewDelegateAndDataSource remains about the data. It simply reports when the user has selected a piece of data. Your viewcontroller can then decide how to manage views to deal with that.

I would recommend renaming your rowTapped method, though. I'd make it more descriptive, and depending on your setup you might want to pass a parameter so that your viewcontroller knows what content it needs to display. Something like:

- (void)userDidSelectMatch:(YBMatch *)match;

or something similar (just guessing at your data structure, there), might be a bit more meaningful?