简体   繁体   中英

Add objects to an Array from another View Controller

I have a HomeViewController which has a tableView populated with the array tableViewArray (originally empty). When I tap on a barButton, I segue modally to another View Controller called OutsideViewController which has another tableView populated by a different array.

What I would like to do is the following:

When I tap on a row in my OutsideViewController , I would like to add the selected string value to the tableViewArray so that when I go back to HomeViewController , the tableView has that new item listed in the tableView.

So far, this is what I have tried:

In the -didSelectRowAtIndexPath method of my OutsideViewController.m I have this piece of code:

NSString *selectedRow = [outsideArray objectAtIndex:indexPath.row];
NSMutableArray *temporaryArray = [NSMutableArray arrayWithObject:selectedRow];

HomeViewController *homeVC = [[HomeViewController alloc] init];
homeVC.tableViewArray = temporaryArray;

That code works but the tableView in HomeViewController is still empty when I return. Do I have to reload the tableView data? Am I doing this right?

This is how I have set up my View Controllers in Storyboard:

HomeViewController -(modal segue)-> Navigation Controller --> OutsideViewController

Also, the return from OutsideViewController to HomeViewController is done by this line of code:

[self dismissViewControllerAnimated:YES completion:^{ }];

What you're doing wrong is you're allocationg a new HomeViewController . What I would do is keeep a reference to your HomeViewController in your OutsideViewController . Here is how.

First, in OutsideViewController.h , create a property, like this :

@property (nonatomic, weak) HomeViewController *homeVC;

Don't forget to add @class HomeViewController; in your .h, and #import "HomeViewController.h" in your .m

In HomeViewController , implement the prepareForSegue: method like this (replace ModalSegueIdentifier with your segue's identifier) :

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"ModalSegueIdentifier"]) {
        OutsideViewController *modalVC = (OutsideViewController*)segue.destinationViewController;
        modalVC.homeVC = self;
    }
}

Then, in OutsideViewController.m , instead of doing :

HomeViewController *homeVC = [[HomeViewController alloc] init];
homeVC.tableViewArray = temporaryArray;

Do this :

_homeVC.tableViewArray = temporaryArray;

When you leave your modal VC, your HomeVC will have the correct array. Don't forget to refresh your UITableView !

NB: Of course, there are many other ways, and it's maybe not the best one. But still, it should work.

You can achieve this too using delegation. You have to create a protocol in your OutsideViewController with a method that is responsible for sending the new object to your HomeViewController . Do this in OutsideViewController.h:

@protocol OutsideViewDelegate <NSObject>
- (void)OutsideViewController:(OutsideViewController *)controller didAddObject:(NSString *)object;
@end

In the implementation file you have to change a little bit the didSelectRowAtIndexPath: method:

NSString *selectedRow = [outsideArray objectAtIndex:indexPath.row];
[self.delegate OutsideViewController:self didAddObject:selectedRow];

In your HomeViewController.h you have to make your class conforms to the protocol:

@interface HomeViewController : UIViewController <OutsideViewDelegate>

After, create a property for the delegate:

@property (nonatomic, weak) id <OutsideViewDelegate> delegate;

To finish the process, implement the protocol in your HomeViewController.m to receive the new object from the OutsideViewController:

- (void)OutsideViewController:(OutsideViewController *)controller didAddObject:(NSString *)object
{
     if (object != nil)
     {
          [self.tableViewArray addObject:object];
     }

     [self dismissViewControllerAnimated:YES completion:nil];
}

The code above depends of if your tableViewArray object is mutable or not. If it's not, you can change the type of the object argument in the protocol method to an inmutable array object and just assign tableViewArray to the new array.

EDIT:

In the prepareForSegue: method don't forget to set the delegate:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"SEGUE_IDENTIFIER"]) {
        OutsideViewController *outsideVC = (OutsideViewController *)[segue destinationViewController];
        [outsideVC setDelegate:self];
    }
}

First of all make sure you alloc , init your tableViewArray in HomeViewController

Second , In this line

HomeViewController *homeVC = [[HomeViewController alloc] init]

you are creating a new reference to your HomeViewController which is not correct, you need to pass correct reference, possibly creating HomeViewController variable in your OutsideViewController

Even though you correctly do first and second suggestion you will still see an empty tableview because you dont reload the tableview, somehow you need to fire [self.tableview reloadData]; method.

That means; you need to learn Delegate or NSNotifications pattern to communicate between child->parent scenarios

How do I set up a simple delegate to communicate between two view controllers?

http://mobile.tutsplus.com/tutorials/iphone/ios-sdk_nsnotificationcenter/

For your question just create a delegate in your Outside ; in your OutsideViewController.h

#import <UIKit/UIKit.h>

@protocol OutsideDelegate;

@interface{}//bunch of interface stuff

// Declare a property for the delegate
@property (weak) id <OutsideDelegate> delegate;
@end

// Protocol Header
@protocol OutsideDelegate <NSObject>
@optional
- (void)dismissPop:(NSMutableArray *)list;
@end

in your OutsideViewController.m

@synthesize delegate;


//run delegate method
[delegate dismissPop:temporaryArray];
[self dismissViewControllerAnimated:YES completion:^{ }];

in your HomeViewController.h

#import "OutsideViewController.h"
@interface OutsideViewController : UITableViewController<OutsideDelegate>
{}
@property (strong, nonatomic) OutsideViewController *pvc;

in your HomeViewController.m

@synthesize pvc;

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([[segue identifier] isEqualToString:@"your segue"]) {
        pvc = [segue destinationViewController];
        [pvc setDelegate:self];
    }
}
// delegate callback function

- (void)dismissPop:(NSMutableArray *)list {

    self.tableViewArray=list;
    [self.tableView reloadData];
}

Another Solution Would be

Change your view stack to this:

Navigation Controller --> HomeViewController -(push segue)--> OutsideViewController

and apply rdurand 's answer

and add this to your HomeViewController :

-(void)viewDidAppear:(BOOL)animated
{
   [self.tableview reloadData];
}

In this solution since you are just push-pop viewcontrollers in a nabigation stack viewDidAppear will be called in HomeViewController everytime when you pop OutsideViewController.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM