Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>"Passing data to the destination Controller" when a segue is triggered will be achieved by overriding method <code>prepareForSegue:sender:</code>.</p> <p>Generally, you pass <em>data</em> and NOT the source view controller, to the destination view controller. "data" may be a certain aspect of your application "model". It's an object like "User", or perhaps an array containing "User", etc.</p> <p>The <em>destination</em> view controller shall <em>not</em> have any knowledge of the <em>source</em> view controller. That means, the destination view controller does not need to import the header of the source view controller.</p> <p>On the other hand, the <em>source</em> view controller <em>may</em> have knowledge of the concrete class of the <em>destination</em> view controller or a <em>base</em> class of the destination view controller, and thus will import the header of the destination view controller.</p> <p>See: <a href="https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html#//apple_ref/doc/uid/TP40007457-CH8-SW4">Configuring the Destination Controller When a Segue is Triggered</a></p> <p>If you need some sort of "communication protocol" between the source and the destination, you might employ <em>Delegation</em> to communicate with other view controllers. This involves the definition of a @protocol (e.g. having a method <code>doneButton</code>) and a property <code>delegate</code> which is defined in the destination view controller. The protocol should be defined in the header of the destination view controller, if it's <em>specific</em> to the destination view controller. Usually, you define tho protocol from the view point of the destination controller, and not from the requirements of the source controller.</p> <p>The source view controller then creates a delegate (unless, it itself is it already) and sets the <code>delegate</code> of of the destination view controller. The destination view controller will send the delegate methods to the delegate, and the delegate handles it.</p> <p>Now, passing "data" from a VC_A to VC_B should be straight forward. You should read a few examples which use <code>prepareForSegue:sender:</code>. For example, the <em>destination</em> view controller may have a property <code>data</code> which represents the <em>thing</em> it should display. The source view controller must set this property in <code>prepareForSegue:sender:</code>.</p> <p>Passing data from VC_A over VC_B to VC_C should be straight forward as well. </p> <p>Note: Each view controller may <em>tailor</em> (separate, modify, prepare, slice, transform, etc.) <em>its</em> <code>data</code> to make it a suitable <code>data</code> for the <em>next</em> view controller.</p> <hr> <p>If VC_C needs data that is not available in its source view controller VC_B, then there are a couple of approaches to solve this. However, this is usually a sign of <em>bad design</em>.</p> <p>You <em>could</em> have an application model, which is <em>global</em>. Suppose, your "application model" is an object of type <code>Document</code>. Suppose, at any time there is only <em>one</em> instance of that application model. Then, the model is a "Singleton", which <em>could</em> be accessed from anywhere in your app like so:</p> <pre><code>Document* document = [Document sharedDocument]; </code></pre> <p>However, the preferred way to get an instance of a model is in the <em>first</em> view controller which requires access to it, in this case: VC_A.</p> <p>Then, VC_A passes a <code>Document</code> instance to the next view controller VC_B. And VC_B passes the document object to VC_C.</p> <p>You should read the official documentation "<a href="https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html">View Controller Programming Guide for iOS</a>".</p> <hr> <h3>Example 1</h3> <p>Suppose, you have a list "Users". The list should be displayed in a table view controller, and there should also be a detail view, showing details of one User.</p> <p>The table view controller will have a "data" property <code>users</code>:</p> <p>In <strong>UsersTableViewController.h</strong>:</p> <pre><code>@interface UsersTableViewController : UIViewController @property (nonatomic, readonly) NSArray* users; @end </code></pre> <p>(Strictly, this <code>user</code> property doesn't need to be public. For example, if the table view internally obtains the list of users itself, there is not need to access it from outside. </p> <p>The "users" array is the <em>data</em> of the table view which shall be displayed in rows. Each row shows a "summary" of a user.</p> <p>More details of a user should be displayed in a <em>detail view controller</em>. The detail view controller's data is a single user of type <code>User</code>.</p> <p>When the user tabs a certain row in the table view, the detail view controller will be displayed. Before it will be displayed, the table view controller must configure the detail view controller: the table view controller assigns the detail view controller's "data property" the current selected <em>user</em>. Thus, the detail view controller should have a <em>public</em> property <code>user</code>:</p> <pre><code>@interface UserViewController : UIViewController @property (nonatomic) User* user; @end </code></pre> <p>The table view controller configures the detail view controller in <code>prepareForSegue:sender:</code>:</p> <p>In <strong>UsersTableViewController.m</strong></p> <pre><code>- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"ShowUserDetails"]) { UserViewController* userViewController = [segue destinationViewController]; userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row]; } } </code></pre> <hr> <h3>Example 2</h3> <p>The second example is more complex and uses "Delegation" as a means to establish a communication between controllers.</p> <p><strong>Caution:</strong> </p> <blockquote> <p>This is not a complete example. The purpose of this example shall demonstrate how to use "Delegation". A full featured implementation of data tasks as shown in the example will require significant more effort. In this scenarios like these, "Delegation" will be the most preferred approach to accomplish this (IMHO).</p> </blockquote> <p>Suppose we want to </p> <ul> <li>Show a User</li> <li>Modify (edit) a User </li> <li>Create New a User, and </li> <li>Delete a User</li> </ul> <p>from within the detail view.</p> <p>These "data tasks" shall not be performed by the detail view controller <em>itself</em>, instead a <em>delegate</em> is responsible for these data tasks.</p> <p>These data actions shall be handled by the delegate:</p> <pre><code>@protocol UserDataSourceDelegateProtocol &lt;NSObject&gt; - (User*) viewControllerUser:(UserViewControllerBase*)viewController; - (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user; - (void) viewController:(UserViewControllerBase*)viewController dismissWithDeletedUser:(User*)user; - (void) viewController:(UserViewControllerBase*)viewController dismissWithCreatedUser:(User*)user; @end </code></pre> <p>This protocol reflects the basic CRUD methods (Create, Read, Update, Delete).</p> <p>Again, we don't want the Detail View Controller <em>itself</em> to perform these data methods, but instead this will be performed by an instance implementing the <code>UserDataSourceDelegateProtocol</code>. The detail view controller has a property of this delegate, and it sends these "data tasks" to the delegate.</p> <p>There may be several detail view controllers, all subclasses of abstract class <code>UserViewControllerBase</code> which handle the <em>show</em>, <em>edit</em> and <em>create</em> tasks. Deletion of a user can be performed in the table view and in the "Show User" view controller:</p> <ul> <li><code>ShowUserViewController</code></li> <li><code>EditUserViewController</code></li> <li><code>NewUserViewController</code></li> </ul> <p>For example The <code>EditUserViewController</code> will send <code>viewController:dismissWithUpdatedUser:</code> when the user tabs the "back" button AND if the user has modified the user object. Now, the delegate may or may not allow to dismiss the detail view. It may disallow it when there are validation errors for example.</p> <p>The <code>UserDataSourceDelegateProtocol</code> protocol <em>may</em> be implemented in the root view controller, the table view controller for example. However, a separate class whose sole responsibility is to handle data tasks may be more appropriate. In the sample below, the table view controller will also be this data handler.</p> <p>The <code>UserDataSourceDelegateProtocol</code> may be defined in an extra header. </p> <p>In <strong>UsersTableViewController.m</strong>:</p> <pre><code>#import "UserDataSourceDelegateProtocol.h" #import "ShowUserViewController.h" @interface UsersTableViewController () &lt;UserDataSourceDelegateProtocol&gt; @property (nonatomic, readonly) NSArray* users; @end // This delegate will be called when the detail view controller request // the user object which shall be displayed. - (User*) viewControllerUser:(UserViewControllerBase*)viewController { return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row]; } </code></pre> <p>Here, the Table View Controller configures the Show User Detail View Controller:</p> <pre><code>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:UserShowSegueID]) { ShowUserViewController* showViewController = segue.destinationViewController; showViewController.delegate = self; // Data Source Handler is self } } </code></pre> <p>The "Edit User" view controller is usually a destination view controller of the "Show User" view controller, which gets viewed when the user tabs the "Edit" button.</p> <p>The "Show User" view controller will setup the delegate for the "Edit User" view controller gets the same delegate:</p> <p>In <strong>ShowUserViewController.m</strong></p> <pre><code>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:UserEditSegueID]) { EditUserViewController* editViewController = segue.destinationViewController; editViewController.delegate = self.delegate; // pass through the data source hanlder } } </code></pre> <p>The data delegate may handle an updated user as follows:</p> <p>In <strong>UsersTableViewController.m</strong>:</p> <pre><code>- (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user { if (/* is valid user and can be saved */) { [viewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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