Reputation: 91949
Passing data between two view controllers seems to have been solved using delegates. My situation is little different and since I am new I don't know if I can solve this with delegates.
I have 3 view controllers. GrandParent
, Parent
and Child
.
GrandParent
instantiates Parent
that shows list of CategoryGroups
.
Clicking on a CategoryGroup
instantiates Child
View Controller that shows list of Categories
.
I want that when user clicks on any Category
, GrandParent
gets to know the Category
being clicked.
What I have now?
On Child.h
view controller
@protocol CategorySelectDelegate<NSObject>
- (void) categorySelected:(CategoryModel *) categoryModel;
@end
On Child.m
view controller
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"selected category:%@", _categories[(NSUInteger) indexPath.row]);
[self.delegate categorySelected:_categories[(NSUInteger) indexPath.row]];
[self dismissViewControllerAnimated:YES completion:nil];
}
On GrandParent.h
@interface GrandParent : UIViewController<CategorySelectDelegate>
On GrandParent.m
- (void)viewDidLoad {
[super viewDidLoad];
ChildViewController *categoryViewController = [[ChildViewController alloc] init];
childViewController.delegate = self;
}
- (void)categorySelected:(CategoryModel *)categoryModel {
_categoryLabel.text = categoryModel.name;
NSLog(@"categoryLabel:%@", _categoryLabel.text);
}
But I know this is incorrect since GrandParent
is not the one instantiating Child
directly, its is always parent who gives birth to Child
Question
- How can I pass the categoryModel
from Child
to GrandParent
?
- In general, how can I pass a data from one Child Controller back to any Ancestor Controller?
UPDATE
For now, I have added 2 delegates to solve this problem
a.) 1 delegate from Child
to Parent
b.) 1 delegate from Parent
to GrandParent
This works but I don't think it is a good design is data needs to be passed between 2 or more view controllers since one will end up creating new delegates to pass values.
Upvotes: 0
Views: 360
Reputation: 3805
I had more or less same use case, and i preferred to go with the notification, as its seems to be loose coupled object,
making delegate just for exchanging data would not be a good choice.
Please refer How Best to Use Delegates and Notifications which says,
Notifications result in loose coupling between objects. The coupling is loose because the object sending a notification doesn't know what is listening to the notification. This loose coupling can be extremely powerful because multiple objects can all register to listen to the same notification So down the line, if some other view controller or any other widgets wants to handle data, it can be achieved easily without setting one more delegate.
but this line also holds good
The fact that notifications and delegates provide such different coupling are an indicator that they should be used in different scenarios. If table view used notifications instead of a delegate, then all classes that use a table view could choose different method names for each notification. This would make it hard to understand code as you would need to go and find the notification registration to work out which method is called. With a delegate, it's obvious: all classes that use a table view are enforced to be structured in the same manner.
Upvotes: 1
Reputation: 3766
If you want to use delegate then there is no way but propagating the GrandParent to Child as a delegate so that it can send callback to GrandParent when category is selected.
Alternatively you can post NSNotification from child when category is selected and add GrandParent as a observer to get the notification.
Upvotes: 0
Reputation: 5061
Interesting problem you have.
You can establish a set of global protocols that can be subscribed to by any object and pass around who receives the messages. This can be as easy as building a separate .h
So, as the parent builds the child, the parent must set the grandparent.delegate = child before presenting that child view controller.
And then of course as the child is removed and the parent shown again, the delegate needs to be set back.
Upvotes: 0