iPhoneNoob
iPhoneNoob

Reputation: 173

calling didSelectRowAtIndexPath from other ViewController not responding iPad

I want to change the selected row in the table (in MasterViewController) from a button on a detailViewController. I know that I cannot call didSelectRowAtIndexPath because it is a delegate method. I tried using selectRowAtIndexPath but that does not invoke the didSelectRowAtIndexPath nor the willSelectRowAtIndexPath method. As suggsted here, https://stackoverflow.com/a/7496926/1050722 it is possible to some new method and then call that method from the other ViewController (detailViewController), but how should that method look like?

Here is some code:

MasterViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath   
{
    [self pushDetailViewController:indexPath];
}

-(void)pushDetailViewController:(NSIndexPath *)indexPath
{        
    if (!self.detailViewController) {
        self.detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
    }
    [self.navigationController pushViewController:self.detailViewController animated:YES];
    NSLog(@"pushDetailviewC and index %@", indexPath);
}

DetailViewController.m

-(IBAction)nextItem
{
    MasterViewController *mVc = [[MasterViewController alloc] init];
    [mVc pushDetailViewController:[NSIndexPath indexPathForRow:0 inSection:0]];
}

Can someone give me an example to fix this? Thanks.

EDIT: Here is the new code

MasterViewController.m

   - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self pushDetailViewController:indexPath];

}

-(void)pushDetailViewController:(NSIndexPath *)indexPath{

    if (!self.detailViewController) {
        self.detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
    }
    self.detailViewController.mVc = self;
    [self.navigationController pushViewController:self.detailViewController animated:YES];
    NSLog(@"pushDetailviewC and index %@", indexPath);
}

DetailViewController.h

#import <UIKit/UIKit.h>
#import "MasterViewController.h"

@interface DetailViewController : UIViewController <UISplitViewControllerDelegate, UITableViewDelegate>

@property (strong, nonatomic) id detailItem;
@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@property (nonatomic, retain) MasterViewController *mVc;

DetailViewCOntroller.m

-(IBAction)test{
    //MasterViewController *mVc = [[MasterViewController alloc] init];
    [self.mVc pushDetailViewController:[NSIndexPath indexPathForRow:0 inSection:0]];
}

It does not call the NSLog part of the method and it is not selecting the row...

Upvotes: 4

Views: 4470

Answers (2)

NJones
NJones

Reputation: 27147

This answer is iPad specific as per your question.

The iPad version of the Master/Detail template uses a UISplitViewController two split the screen as you see it. This UISplitViewController instance keeps references to both of your navigations controllers. Which keep reference to your topmost view controllers. Here is sample code, do not use it verbatim except to test since it contains no error checking.

// Picking some arbitrary row 
NSUInteger desiredRow = 3;//???
// The Master navigation controller is at index zero in the template, you can check in your app delegate's didFinishLaunching: method
UINavigationController *masterController = [self.splitViewController.viewControllers objectAtIndex:0];
// Next we want a reference to the topmost viewController again you shouldn't assume it's a UITableViewController
UITableViewController *tableController = (UITableViewController *)masterController.visibleViewController;
// Next we get the reference to the tableview in-question
UITableView *tableView = tableController.tableView;
// We translate our desired row to an index path
NSIndexPath *path = [NSIndexPath indexPathForRow:desiredRow inSection:0];
// We select the row , again this will not call didSelectRowAtIndexPath:
[tableView selectRowAtIndexPath:path animated:YES scrollPosition:UITableViewScrollPositionNone];
// We call didSelectRowAtIndexPath: on the tableview's delegate
[tableView.delegate tableView:tableView didSelectRowAtIndexPath:path];

When I put this code in an IBAction method in the detail view controller the linked button performs the appropriate actions, both selects the row and pushes a VC, as if I had selected the row by touch.

Upvotes: 12

Walter
Walter

Reputation: 5887

In DetailViewController.h add a property to the object that points to the MasterViewController. You will also need to import the MasterViewController.h so something like

#import "MasterViewController"

...

@property (nonatomic, retain) MasterViewController *mVc;

...

Don't forget in DetailViewController.m to @synthesize mVc;

Now in your pushDetailViewController you add a reference to join the two objects

if (!self.detailViewController) {
    self.detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
}
[self.detailViewController.mVc = self]; // New line
[self.navigationController pushViewController:self.detailViewController animated:YES];

Then in the DetailViewController you reference the object

-(IBAction)nextItem{
[self.mVc pushDetailViewController:[NSIndexPath indexPathForRow:0 inSection:0]];
}  

I think another issue you were having was alloc'ing a new version of mVC each time you click the nextItem button. IOS will happily let you make lots of MasterViewController objects and makes a new one each time you alloc it. You wanted just to get a handle to your original MasterViewController.
Another approach would be to explore using the parent methods to reference the MasterViewController. But I wanted to show you how to do this with an explicit property since I thought it would be clearer.

Also, this may or may not fix all of your issues, but it hopefully at least shows you how to talk back to the actual MasterViewController.

Upvotes: 3

Related Questions