Question

I implemented a custom UIViewController which has multiple child view controllers (mainly by using the storyboard's Container View but not only).

I'm wondering what is the best way for the "root" view controller to send a message to its children, taking into account that the child(s) view controller(s) concerned by the message sent is not necessarily a direct child of the "root" view controller ?

For example:

View controllers hierarchy

I want to send a message from #0 to view controllers #1 and #4. The naïve implementation is to iterate over the child of #0 and send them the message, like so:

for (UIViewController *childVC in self.childViewControllers)
{
    if ([childVC respondsToSelector:@selector(myMessage:)])
    {
        [childVC performSelector@selector(myMessage:)];
    }
}

But it simply doesn't work, because #3 will receive the message (or probably not if it is a UINavigationController and I'm calling a custom method) and don't propagate it to its children (here #4).

So is there a possibility to send a message to one's children, and let the message propagate through the UIViewController hierarchy ?

If not, an alternative would be to use the NSNotificationCenter, make the children interested in the message (#1 and #4) observe for a notification, and make the root view controller post a notification when necessary. But I find it a bit of an overkill only to dispatch a message to two children.

Was it helpful?

Solution

I tend to avoid NSNotificationCenter, because if one is not careful it will create a bit of Spaghetti Code. Still, in this case I would use it, because it's even more of a overkill to taking of the logic of how the message should propagate between the childsViewControllers and possibility the ochildsViewControllers's childs.

OTHER TIPS

I think going through NSNotificationCenter is the best way to go. Each child view controller can decide for themselves what notifications they want to respond to; it takes the responsibility of filtering away from the object posting the notification.

You could also do something like this, but I'm not saying its a good idea:

@interface UIViewController (ReverseResponder)

- (void)reverseRespond:(SEL)selector withObject:(id)object;

@end

@implementation UIViewController (ReverseResponder)

- (void)reverseRespond:(SEL)selector withObject:(id)object
{
    if ([self respondsToSelector:selector]) {
        [self performSelector:selector withObject:object];
    }

    for (UIViewController* childViewController in self.childViewControllers) {
        [childViewController reverseRespond:selector withObject:object];
    }
}

You can access all of your children with self.childViewControllers, and pass a specific index to get to a particular child. To get to 4, you'll have to access 3's topViewController.

UIViewController *child4 = [(UINavigationController *)self.childViewControllers[2] topViewController];

Whether this is a good way to do this, depends on what you're trying to do. Why are you sending messages down to this level?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top