Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This question seems to be very popular here on stackoverflow so I thought I would try and give a better answer to help out people starting in the world of iOS like me.</p> <p>I hope this answer is clear enough for people to understand and that I have not missed anything.</p> <p><strong>Passing Data Forward</strong></p> <p>Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.</p> <p>For this example we will have <code>ViewControllerA</code> and <code>ViewControllerB</code></p> <p>To pass a <code>BOOL</code> value from <code>ViewControllerA</code> to <code>ViewControllerB</code> we would do the following.</p> <ol> <li><p>in <code>ViewControllerB.h</code> create a property for the <code>BOOL</code></p> <pre><code>@property (nonatomic, assign) BOOL isSomethingEnabled; </code></pre></li> <li><p>in <code>ViewControllerA</code> you need to tell it about <code>ViewControllerB</code> so use an </p> <pre><code>#import "ViewControllerB.h" </code></pre> <p>Then where you want to load the view eg. <code>didSelectRowAtIndex</code> or some <code>IBAction</code> you need to set the property in <code>ViewControllerB</code> before you push it onto nav stack.</p> <pre><code>ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.isSomethingEnabled = YES; [self pushViewController:viewControllerB animated:YES]; </code></pre> <p>This will set <code>isSomethingEnabled</code> in <code>ViewControllerB</code> to <code>BOOL</code> value <code>YES</code>.</p></li> </ol> <p><strong>Passing Data Forward using Segues</strong></p> <p>If you are using Storyboards you are most likely using segues and will need this procedure to pass data forward. This is similar to the above but instead of passing the data before you push the view controller, you use a method called</p> <pre><code>-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender </code></pre> <p>So to pass a <code>BOOL</code> from <code>ViewControllerA</code> to <code>ViewControllerB</code> we would do the following:</p> <ol> <li><p>in <code>ViewControllerB.h</code> create a property for the <code>BOOL</code></p> <pre><code>@property (nonatomic, assign) BOOL isSomethingEnabled; </code></pre></li> <li><p>in <code>ViewControllerA</code> you need to tell it about <code>ViewControllerB</code> so use an</p> <pre><code>#import "ViewControllerB.h" </code></pre></li> <li><p>Create a the segue from <code>ViewControllerA</code> to <code>ViewControllerB</code> on the storyboard and give it an identifier, in this example we'll call it <code>"showDetailSegue"</code></p></li> <li><p>Next we need to add the method to <code>ViewControllerA</code> that is called when any segue is performed, because of this we need to detect which segue was called and then do something. In our example we will check for <code>"showDetailSegue"</code> and if thats performed we will pass our <code>BOOL</code> value to <code>ViewControllerB</code></p> <pre><code>-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ if([segue.identifier isEqualToString:@"showDetailSegue"]){ ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController; controller.isSomethingEnabled = YES; } } </code></pre> <p>If you have your views embedded in a navigation controller you need to change the method above slightly to the following</p> <pre><code>-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ if([segue.identifier isEqualToString:@"showDetailSegue"]){ UINavigationController *navController = (UINavigationController *)segue.destinationViewController; ViewControllerB *controller = (ViewControllerB *)navController.topViewController; controller.isSomethingEnabled = YES; } } </code></pre> <p>This will set <code>isSomethingEnabled</code> in <code>ViewControllerB</code> to <code>BOOL</code> value <code>YES</code>.</p></li> </ol> <p><strong>Passing Data Back</strong></p> <p>To pass data back from <code>ViewControllerB</code> to <code>ViewControllerA</code> you need to use <em>Protocols and Delegates</em> or <em>Blocks</em>, the latter can be used as a loosely coupled mechanism for callbacks.</p> <p>To do this we will make <code>ViewControllerA</code> a delegate of <code>ViewControllerB</code>. This allows <code>ViewControllerB</code> to send a message back to <code>ViewControllerA</code> enabling us to send data back.</p> <p>For <code>ViewControllerA</code> to be delegate of <code>ViewControllerB</code> it must conform to <code>ViewControllerB</code>'s protocol which we have to specify. This tells <code>ViewControllerA</code> which methods it must implement.</p> <ol> <li><p>In <code>ViewControllerB.h</code>, below the <code>#import</code>, but above <code>@interface</code> you specify the protocol.</p> <pre><code>@class ViewControllerB; @protocol ViewControllerBDelegate &lt;NSObject&gt; - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; @end </code></pre></li> <li><p>next still in the <code>ViewControllerB.h</code> you need to setup a <code>delegate</code> property and synthesize in <code>ViewControllerB.m</code></p> <pre><code>@property (nonatomic, weak) id &lt;ViewControllerBDelegate&gt; delegate; </code></pre></li> <li><p>In <code>ViewControllerB</code> we call a message on the <code>delegate</code> when we pop the view controller.</p> <pre><code>NSString *itemToPassBack = @"Pass this value back to ViewControllerA"; [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack]; </code></pre></li> <li><p>That's it for <code>ViewControllerB</code>. Now in <code>ViewControllerA.h</code>, tell <code>ViewControllerA</code> to import <code>ViewControllerB</code> and conform to its protocol.</p> <pre><code>#import "ViewControllerB.h" @interface ViewControllerA : UIViewController &lt;ViewControllerBDelegate&gt; </code></pre></li> <li><p>In <code>ViewControllerA.m</code> implement the following method from our protocol</p> <pre><code>- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item { NSLog(@"This was returned from ViewControllerB %@",item); } </code></pre></li> <li><p>Before pushing <code>viewControllerB</code> to navigation stack we need to tell <code>ViewControllerB</code> that <code>ViewControllerA</code> is its delegate, otherwise we will get an error.</p> <pre><code>ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.delegate = self [[self navigationController] pushViewController:viewControllerB animated:YES]; </code></pre></li> </ol> <hr> <h3>References</h3> <ul> <li><a href="http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html#//apple_ref/doc/uid/TP40007457-CH8-SW9" rel="noreferrer">Using Delegation to Communicate With Other View Controllers</a> in the <em>View Controller Programming Guide</em></li> <li><a href="https://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html" rel="noreferrer">Delegate Pattern</a></li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload