Passing Row Index of TableViewCell (custom) to another view controller I have been trying to achieve the below requirements to get them working.  Am I doing it the right way?


We have a table with customised Cell (say: firstViewController)
Customised Cell has a button, click event in this button, and carries row index value to another view controller.  In this view controller I will use this row index to access the data model from first view controller.


Annotation: Each row has values associated with unique Dictionary value in Array based on row Index.

Pseudo Code: (pasted only necessary code)

FirstViewController.h

 @interface firstViewController : UIViewController &lt;UITableViewDataSource, UITableViewDelegate&gt;


 @property NSMutableArray *MasterRecords;   //  Each element in Array is dictionary. 
 @property (weak, nonatomic) IBOutlet UITableView *tblMasterTable;
 @end


FirstViewController.m

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    static NSString *columnIdfer = @"items";
    StudentCell *cell = (StudentCell *)[tableView dequeueReusableCellWithIdentifier:columnIdfer];
    if ( cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"StudentCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }


    if (indexPath.row &lt; [self.MasterRecords count])
    {

        cell.iRecordIndex = indexPath.row;
    }


    return cell;

}


In the above code I set the iRecordIndex to IndexPath.row

StudentCell.h

@interface StudentCell : UITableViewCell
@property NSInteger iRecordIndex;
@property (weak, nonatomic) IBOutlet UIButton *btnSubmit;  // It pushes viewController.
@end


StudentCell.m

- (IBAction)btnSubmitPressed:(id)sender {

     NextViewController *sVC = [[NextViewController alloc]     initWithRecIndex:@"NextViewController" bundle:nil Index:self.iRecordIndex];

  // Pushing NextViewController to NavigationViewController.
}


NextViewController.h

@interface NextViewController : UIViewController &lt;MKMapViewDelegate&gt;
- (id)initWithRecIndex:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil  Index:(NSInteger )iRecIndex;
@property NSInteger iRecordIndex;
@end


NextViewController.m

 - (id)initWithRecIndex:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil  Index:(NSInteger )iRecIndex
{
      self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        self.iRecordIndex = iRecIndex;
    }

    return self;
}

-(void) viewWillAppear:(BOOL)animated
{
    //Get FistViewController.   say  ==&gt; fvc.

    NSMutableArray *mRec = [fvc MasterRecords];
    NSMutableDictionary *mDict = [mRec objectAtIndex:self.iRecordIndex];

    NSLog (@" value1 is %@ ", [mDict valueForKey:@"value1"]);
    NSLog (@" value2 is %@ ", [mDict valueForKey:@"value2"]);

   // Using value1, and value2 to display MKMapView.
}


Is this the right approach, or should I improve it?
There are several problems with your code.

First, you should use more descriptive names for your instance variables/properties.

 @interface firstViewController : UIViewController &lt;UITableViewDataSource, UITableViewDelegate&gt;


Class names in Cocoa are conventionally named with a prefix in capitals followed by the name of the class in TitleCase.

 @property NSMutableArray *MasterRecords;   //  Each element in Array is dictionary. 


Names of instance variables and properties should be in camelCase.



    static NSString *columnIdfer = @"items";
StudentCell *cell = (StudentCell *)[tableView dequeueReusableCellWithIdentifier:columnIdfer];
if ( cell == nil)
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"StudentCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];
}


You should register the nib of your cell before using your table view. This eliminates the need for instantiating a cell yourself every time it's need, and also does away with if (cell == nil), as dequeueReusableCellWithIdentifier: will always return a valid cell, provided you set the table view up properly. Proper code with these things in mind would be:

- (void)viewDidLoad
{
    [super viewDidLoad];
    . . .
    [self.tblMasterTable registerNib:[UINib nibWithNibName:@"StudentCell" bundle:nil];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    StudentCell *cell = (StudentCell *)[tableView dequeueReusableCellWithIdentifier:@"items"];
    . . .
    return cell;
}




- (IBAction)btnSubmitPressed:(id)sender {
    NextViewController *sVC = [[NextViewController alloc]     initWithRecIndex:@"NextViewController" bundle:nil Index:self.iRecordIndex];
    // Pushing NextViewController to NavigationViewController.
}


Following the MVC pattern, your view should know nothing about your controllers. You could reimplement the above using a view controller as the cell's delegate, passing a suitable identifier in a suitable method. The delegate view controller could then manage instantiating and presenting/pushing other view controllers.



- (id)initWithRecIndex:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil  Index:(NSInteger )iRecIndex;


Several problems with this. You're specifying the return type as id, but I assume it always returns a NextViewController. As suggested in the comments, current practice is to use instancetype as the return type instead of id. For more information on id vs instancetype check this answer out.

You do not attempt to make a distinction between RecIndex and Index in the method name. The argument names do not match what the method name tells us. The implementation of this method doesn't help matters.



-(void) viewWillAppear:(BOOL)animated
{
//Get FistViewController.   say  ==&gt; fvc.

NSMutableArray *mRec = [fvc MasterRecords];
NSMutableDictionary *mDict = [mRec objectAtIndex:self.iRecordIndex];

NSLog (@" value1 is %@ ", [mDict valueForKey:@"value1"]);
NSLog (@" value2 is %@ ", [mDict valueForKey:@"value2"]);

// Using value1, and value2 to display MKMapView.
}


Inconsistent spacing. Make up your mind about how you want to space out your method implementations/declarations and use that style consistently throughout your code.

CodeReview does not appreciate pseudo-code. Please post all relevant bits of code.

Again, instance variables are badly named. Use more descriptive names.

This view controller should not know much about it's presenting view controller.

It should declare properties for the information it needs to get from its presenting view controller. The presenting view controller can then set these properties up after instantiating but before presenting this view controller.

NextViewController *vc = . . .;
vc.mRec = . . .;

[self.navigationController pushViewController:vc animated:YES];


Or in the prepareForSegue: method if using storyboards.