How to open UITableViewController modally and pass NSMutableArray

Discussion in 'iOS Programming' started by igorland, Mar 21, 2014.

  1. igorland macrumors newbie

    Joined:
    Mar 4, 2014
    #1
    I have a ViewController where I enter a key through a textBox. The entered key pulls out all available records from a database where the same key is found. The list of the records forms NSMutableArray that I pass to UITableViewController, where the user can pick one. Then on the initial ViewController, this value should be selected.

    Two issues:

    1. Is there a way to open the TableViewController as modal and programmatically (not with the StoryBoard)? I have some "if" statements there that should control whether the TableViewController opens.

    2. I cannot pass the array from the ViewController to TableViewController. Since I have no answer for question 1, I am doing it using another button (test). NSLog in UITableViewController tells me that the array there is null.

    UIViewController.h:
    Code:
    @interface IGAViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
    NSString *navigationPoint;
    NSMutableArray *navigationList; // List of all navigation points with the same name
    }
    
    @property (nonatomic,retain, getter=passNavigationList) NSMutableArray *navigationList;
    @property (nonatomic,retain) NSString *navigationPoint;
    
    // Return navigation list
    -(NSMutableArray *) passNavigationList;
    
    UIViewController.mm
    Code:
    @implementation IGAViewController
    
    @synthesize navigationPoint, navigationList;
    
    // Return navigation list
    -(NSMutableArray *) passNavigationList {
        return navigationList;
        NSLog(@"NAVIGATION LIST AGAIN: %@", navigationList);
    }
    
    // Add a Navigation Point
    -(IBAction) addIcaoNavigation:(id)sender {
    
        // Setting up the path to the navigation points database
        pathNav = [[NSBundle mainBundle] pathForResource:@"navdata_nav"
                                                  ofType:@"txt"];
        
        // Text entered in the textfield is assigned as the Navigation Point
        navigationPoint = txtNavIcao.text;
        
         // If the Departure airport is not determined, this will give an error. Determine Departure first.
        if ([txtDepIcao.text isEqual:@""] || portDeparture == nil) {
            // Pop-up message that the airport was not found
            UIAlertView* portNotFoundMsg;
            portNotFoundMsg = [[UIAlertView alloc] initWithTitle:@"No Departure airport"
                                                         message:@"Select the Departure airport first"
                                                        delegate:self
                                               cancelButtonTitle:@"OK"
                                               otherButtonTitles:nil, nil];
            [portNotFoundMsg show];
        }
        
        else {
            
    // Create an object for the Navigation Points and getting data
            IGDNavigation* navObj = [[IGDNavigation alloc] initWithName: navigationPoint navdataPath: pathNav];
            
    // Creating a list of all points with the same code sorted by the distance from departure
    navigationList = [navObj navDataWithPreviousLatitude:depLatitude PreviousLongitude:depLongitude]; 
            
    NSLog(@"NAVIGATION LIST: %@", navigationList);
            
    // Open the UITableViewController
    // THIS IS WHERE HELP FOR Q1 IS NEEDED
    
     
     NSLog(@"NAVIGATION POINT: %@", navigationPoint);
    
    
    UITableViewController.h
    Code:
    @interface IGANavListTableViewController : UITableViewController    {
        NSString *navPoint;
        NSMutableArray *listOfNavPoints;
    }
    
    @property (nonatomic,strong) NSMutableArray *listOfNavPoints;
    @property (nonatomic,strong) NSString *navPoint;
    
    UITableViewController.mm
    Code:
    @implementation IGANavListTableViewController
    
    @synthesize listOfNavPoints, navPoint;
    
    - (id)initWithStyle:(UITableViewStyle)style
    {
        self = [super initWithStyle:style];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        // Pass the list of Navigation Points
        IGAViewController *mainObj = [[IGAViewController alloc] init];
        
        
    // listOfNavPoints = [[NSMutableArray alloc] initWithObjects:@"111",@"222",@"333", nil]; // THIS WORKS!
        
    listOfNavPoints = [mainObj passNavigationList]; // THIS DOES NOT WORK!
        
        // THIS IS JUST TO CHECK IF PASSING WORKS
        navPoint = mainObj.navigationPoint;
        NSLog(@"VIEW DID LOAD: %@", navPoint);
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark - Table view data source
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        // Return the number of sections.
        return 1;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        // Return the number of rows in the section.
        return [listOfNavPoints count];
    }
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
        
        //UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        
        
        // Configure the cell...
        if (cell==nil)  {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
            if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
                cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
            }
        }
        
        cell.textLabel.text = [listOfNavPoints objectAtIndex:indexPath.row];
        
        return cell;
    }
    
    In the end, I have:
    Code:
    NAVIGATION LIST: (
        "NDB|GIG|GERING|41.944356|-103.683|341 Khz|639 nm",
        "NDB|GIG|GINGIN|-31.459722|115.865556|372 Khz|8275 nm"
    )
    
    NAVLIST DID LOAD: (null)
    
    I have been fighting this dilemma for a week already, although it should be a simple thing to do. I would really appreciate people's help!
     
  2. mjohnson1212 macrumors member

    Joined:
    Nov 15, 2007
    #2
    presentViewController will show a view controller modally.

    When you create your subclass of UITableViewController just create a property to pass in the data.
     
  3. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #3
    igorland, which version of Xcode are you using? It looks like you are declaring instance-variables to back your properties and synthesizing them. That is no longer necessary.

    Have you read the View Controller Programming Guide for iOS, particularly the section on "Coordinating Efforts Between View Controllers"?
     
  4. igorland thread starter macrumors newbie

    Joined:
    Mar 4, 2014
    #4
    Hi, guys. Thank you for trying to help. I am still learning and therefore some of the stuff that is obvious to you is not clear to me. So, please bear with me, :eek:

    So, after reading and re-reading tens of articles and forum messages, I still do not see why it is not working. I changed the code. Now it is as follows:

    IGAViewController.h
    Code:
    #import <UIKit/UIKit.h>
    #import "IGDNavigation.h"
    #import "IGANavListTableViewController.h"
    
    @interface IGAViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
        // Navigation points
        NSString *pathNav;
        NSString *navigationPoint;
        NSMutableArray *navigationList; // List of all navigation points with the same name
    }
    
    @property (nonatomic,retain) NSString *navigationPoint;
    
    @property (nonatomic,retain, getter=passNavigationList) NSMutableArray *navigationList;
    
    @property (nonatomic,retain) IBOutlet UITextField *txtNavIcao;
    
    -(IBAction) addIcaoNavigation:(id)sender;
    -(IBAction) test:(id)sender;
    
    @end
    
    IGAViewController.mm
    Code:
    #import "IGAViewController.h"
    
    @interface IGAViewController ()
    
    @property (weak, nonatomic) IBOutlet UIButton *testButton;
    
    @end
    
    @implementation IGAViewController
    
    @synthesize navigationPoint, navigationList;
    
    
    // Add a Navigation Point
    -(IBAction) addIcaoNavigation:(id)sender {
    
        // Setting up the path to the navigation points database
        pathNav = [[NSBundle mainBundle] pathForResource:@"navdata_nav"
                                                  ofType:@"txt"];
        
        // Text entered in the textfield is assigned as the Navigation Point
        navigationPoint = txtNavIcao.text;
        
         // If the Departure airport is not determined, this will give an error. Determine Departure first.
        if ([txtDepIcao.text isEqual:@""] || portDeparture == nil) {
            // Pop-up message that the airport was not found
            UIAlertView* portNotFoundMsg;
            portNotFoundMsg = [[UIAlertView alloc] initWithTitle:@"No Departure airport"
                                                         message:@"Select the Departure airport first"
                                                        delegate:self
                                               cancelButtonTitle:@"OK"
                                               otherButtonTitles:nil, nil];
            [portNotFoundMsg show];
        }
        
        else {
            
            // Create an object for the Navigation Points
            IGDNavigation* navObj = [[IGDNavigation alloc] initWithName: navigationPoint navdataPath: pathNav];
            
            // Creating a list of all points with the same code sorted by the distance from departure
            navigationList = [navObj navDataWithPreviousLatitude:depLatitude PreviousLongitude:depLongitude];
            
            NSLog(@"NAVIGATION LIST: %@", navigationList);
    
        }
    }
    
    
    -(IBAction)test:(id)sender {
        IGANavListTableViewController *listObj = [[IGANavListTableViewController alloc]init];
        
        [listObj loadNavData:navigationList];
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	// Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
    IGANavListTableViewController.h
    Code:
    #import <UIKit/UIKit.h>
    
    @interface IGANavListTableViewController : UITableViewController    {
        NSString *navPoint;
    }
    
    -(void) loadNavData: (NSMutableArray *) nadData;
    -(IBAction)cancel:(id)sender;
    
    @end
    
    IGANavListTableViewController.mm
    Code:
    #import "IGANavListTableViewController.h"
    #import "IGAViewController.h"
    #import "IGDNavigation.h"
    
    @interface IGANavListTableViewController ()
    
    // Declare the mutable array with a list of nav points
    @property NSMutableArray *listOfNavPoints;
    
    @end
    
    @implementation IGANavListTableViewController
    
    
    - (id)initWithStyle:(UITableViewStyle)style
    {
        self = [super initWithStyle:style];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.listOfNavPoints = [[NSMutableArray alloc] init];
    
        // Here _listOfNavPoints is initialized but empty. But it is not empty in the loadNavData method! Do I somehow need to implement that method here again?
        NSLog(@"NAVLIST DID LOAD: %@", _listOfNavPoints);
    }
    
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark - Table view data source
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        // Return the number of sections.
        return 1;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        // Return the number of rows in the section.
        return [_listOfNavPoints count];
    }
    
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"ListPrototypeCell";
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
         
        cell.textLabel.text = [_listOfNavPoints objectAtIndex:indexPath.row];
        
        return cell;
    }
    
    // Passing the value to the original view with the selected navigation point
    
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath  {
        NSLog(@"DID SELECT ROW AT INDEX PATH");
        NSLog(@"Row: %d",indexPath.row);
        // TO DO
    }
    
    
    // This button closes the table with Navigation Points
    -(IBAction)cancel:(id)sender    {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    // This method works!!! returns the array
    -(void) loadNavData: (NSMutableArray *) navData {
        _listOfNavPoints = navData;
        
        NSLog(@"_LISTOFNAVPOINTS: %@",_listOfNavPoints);
    }
    
    @end
    
    By the way, I tried to implement the following in the IGAViewController:
    Code:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"ListPrototypeCell";
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
         
        cell.textLabel.text = [navigationList objectAtIndex:indexPath.row];
        
        return cell;
    }
    
    Still does not work. Cannot believe that it is taking so long! Million thanks, guys!
     
  5. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #5
    In the above code, I see you've alloc/init'd your IGANavListTableViewController, but I can't see where you actually present the view for it.
     
  6. igorland thread starter macrumors newbie

    Joined:
    Mar 4, 2014
    #6
    dejo. Thanks a lot for bearing with me!

    In my -(IBAction)test:(id)sender method, I implement the following method in UITableViewController:

    Code:
    // This method works!!! returns the array
    -(void) loadNavData: (NSMutableArray *) navData {
        _listOfNavPoints = navData;
        
        NSLog(@"_LISTOFNAVPOINTS: %@",_listOfNavPoints);
    }
    
    This code works perfectly well and returns the same array as in navigationList in UIViewController. Now, I assume that _listOfNavPoints is already set, however, when I implement this method:

    Code:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.listOfNavPoints = [[NSMutableArray alloc] init];
    
        // Here _listOfNavPoints is initialized but empty. But it is not empty in the loadNavData method! Do I somehow need to implement that method here again?
        NSLog(@"NAVLIST DID LOAD: %@", _listOfNavPoints);
    }
    
    _listOfNavPoints is empty!

    I now tried this:

    Code:
    @interface IGANavListTableViewController ()
    
    // Declare the mutable array with a list of nav points
    @property NSMutableArray *listOfNavPoints;
    @property NSMutableArray *arrayTemp;
    
    @end
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.listOfNavPoints = [[NSMutableArray alloc] init];
        
        [_listOfNavPoints addObject:_arrayTemp];
    
        NSLog(@"ARRAYTEMP: %@",_arrayTemp);
        NSLog(@"NAVLIST DID LOAD: %@", _listOfNavPoints);
    }
    
    ...
    
    -(void)loadNavData: (NSMutableArray *) navData {
        
        _arrayTemp = [[NSMutableArray alloc] init];
        _arrayTemp = navData;
        
        NSLog(@"_LIST OF NAVIGATION POINTS IN LOADNAVDATA: %@", _arrayTemp);
    
    }
    
    
    _LIST OF NAVIGATION POINTS IN LOADNAVDATA: shows the right array

    but the application crashes, because ARRAYTEM: _tempArray is nil. But WHY?????
     
  7. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #7
    What do you think this line of code does if listOfNavPoints already contains values? Do you think it leaves it alone?

    Given that, please tell us what resources you're using to learn the fundamentals of iOS/Objective-C programming. Be as specific as possible. Your improper use of underscore-starting instance-variables, like _listOfNavPoints (they should only be referenced in init-type methods) show that you don't seem to have a solid grasp of the basics.
     
  8. igorland, Mar 24, 2014
    Last edited: Mar 24, 2014

    igorland thread starter macrumors newbie

    Joined:
    Mar 4, 2014
    #8
    I have included several options of codes here and it looks messy now. In some cases, they are mutually exclusive, and therefore cause the above questions. Sorry if this is the case.

    Xcode inserts it for me otherwise producing errors. I agree, it should have been self.listOfNavPoints.

    I'd rather not include the resources in this thread. I usually try to be right to the point and avoid straying from the topic to the extent possible.
     

Share This Page