kerbelda
kerbelda

Reputation: 345

Pass property from Modal View Controller to Parent

I have a tableview as a parent view controller with a child modal view controller. In the modal view controller, when users tap on a row, I'd like to set the parent's property 'filter.' However, it's just returning null.

How do I pass the NSString filter property back to its parent view? And should I be instantiating a parent view controller in the didSelectRowAtIndexPath method?

UPDATE: Solved using Delegates, followed this tutorial.

Below is the code for the modal view controller:

#import "FilterViewController.h"
#import "ContactsTableViewController.h"


@interface FilterViewController ()

@end

@implementation FilterViewController


- (void)viewDidLoad
{
    [super viewDidLoad];
    self.filterTable.dataSource = self;
    self.filterTable.delegate = self;
    [self performSelector:@selector(retrieveFilteredEvents)];
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.filterEvents count];
}

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

    static NSString *cellIdentifier = @"filterTableCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];


     NSDictionary *tempDict = [self.filterEvents objectAtIndex:indexPath.row];

    self.eventTitle = [tempDict objectForKey:@"eventType"];
    cell.textLabel.text = self.eventTitle;

    return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *tempDict = [self.filterEvents objectAtIndex:indexPath.row];
    NSString *string = [tempDict objectForKey:@"eventType"];

    ContactsTableViewController *contactVC = [[ContactsTableViewController alloc] init];
    contactVC.filter = string;

    [self dismissViewControllerAnimated:YES completion:nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"updateParent" object:nil];
}

#pragma mark - Helper Methods

- (IBAction)done:(id)sender
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

-(void)retrieveFilteredEvents
{
    PFQuery *retrieveEvents = [PFQuery queryWithClassName:@"eventTypes"];
    [retrieveEvents orderByAscending:@"eventOrder"];
    [retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
            self.filterEvents = [[NSArray alloc] initWithArray:objects];
        }
        [self.filterTable reloadData];
    }];

}

@end

Upvotes: 1

Views: 1533

Answers (5)

David Kristensen
David Kristensen

Reputation: 31

If it's a simple property set, you could do

[self.parentViewController performSelector:@selector(setSomething:) withObject:...]

or

[self.presentingViewController performSelector:@selector(setSomething:) withObject:...]

Delegates is a much better way, though :-)

Upvotes: 0

Ankush Agrawal
Ankush Agrawal

Reputation: 395

There are multiple ways to approach this problem. The easiest I think would be setting a property in your parent class that would change every time you update the child.

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *tempDict = [self.filterEvents objectAtIndex:indexPath.row];
    NSString *string = [tempDict objectForKey:@"eventType"];

    self.parentViewController.filter = string;

    [self dismissViewControllerAnimated:YES completion:nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"updateParent" object:nil];
}

The other option would be to use delegates. This is probably a cleaner solution but is not as beginner friendly.

http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html

Upvotes: 3

Lena Bru
Lena Bru

Reputation: 13947

create a protocol

@protocol PassSomeData

-(void)childViewController:(UIViewController *)viewController passedSomeData:(id)data;
@end

create a delegate in the childview controller

@interface ViewControllerThatIsPresentedModally :UIViewController
@property(nonatomic,assign) id<PassSomeData>delegate;
@end

in prepareForSegue of the view controller that is presenting the modal write this

UIViewController *vc = [segue destinationViewController];
if ([vc isKindOfClass:[ViewControllerTahIsPresentedModally class]){
[((ViewControllerThatIsPresentedModally *)vc) setDelegate:self];
}

when your user clicks something that allows some data to be collected you do

[self.delegate viewController:self passedSomeData:yourData];

and your method in the parent view controller will be called with your data

your presenting view controller needs to conform to the PassedSomeData protocol and implement the given method as well

Upvotes: 2

CrimsonChris
CrimsonChris

Reputation: 4651

Alloc init gives you a brand new object, NOT a reference to your existing one. There are a couple of ways to get a reference to your table view. I recommend delegation, it's a flexible approach that will continue to work even if you present your view in a different way than modal.

Upvotes: 2

sergio
sergio

Reputation: 69047

What you are doing here:

ContactsTableViewController *contactVC = [[ContactsTableViewController alloc] init];
contactVC.filter = string;

is instantiating a whole new controller that has nothing to do with the actual controller that presented your FilterViewController.

Try using this, instead, which accesses the view controller that presented FilterViewController:

ContactsTableViewController *contactVC = (ContactsTableViewController*)self.presentingController;
contactVC.filter = string;

Hope this helps.

Upvotes: 3

Related Questions