title: Master-Detail Split View
body: <p>I have an iPhone app that I'm wanting to make a universal app and implement a split view on the iPad.  I have the master view set up so that when the user selects a row, the master view goes to another table view.  When a row is selected in that table view, I want the detail view to show my web view.  This all works but the issue I'm having is when the web view shows on the detail view, it is just getting added to the navigation stack instead of just replacing what is currently there.  This makes it so that the user has to press the back button on the detail view navigation bar in order to make another selection in the master view.  If another selection is made in the master view without pressing the back button on the detail view, the app crashes.</p>
  
  <p>I need to figure out how to have the web view not get added to the navigation stack of the detail view and instead replace the current detail view.</p>
  
  <p>MasterViewController:</p>
  
  <pre><code>#import "KFBMasterViewController.h"
  #import "KFBDetailViewController.h"
  #import "ListViewController.h"
  #import "SocialNetworks.h"
  #import "WebViewController.h"
  
  @interface KFBMasterViewController () {
      NSMutableArray *_objects;
      NSMutableArray *menu;
  }
  @end
  
  @implementation KFBMasterViewController
  
  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  {
      self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
      if (self) {
          self.title = NSLocalizedString(@"Master", @"Master");
          self.clearsSelectionOnViewWillAppear = NO;
          self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
      }
      return self;
  }
  
  - (void)viewDidLoad
  {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
      // self.navigationItem.leftBarButtonItem = self.editButtonItem;
  
      // UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
      // self.navigationItem.rightBarButtonItem = addButton;
  
      menu = [NSMutableArray arrayWithObjects:@"Home", @"Public Affairs", @"Action Alerts", @"Market Updates", @"Ag Stories", @"KFB News", @"Member Benefits", @"Monthly Video", @"Photos", @"Social Media", @"About Us", @"Contact Us", @"KYFB.com", nil];
  }
  
  - (void)didReceiveMemoryWarning
  {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
  }
  
  - (void)insertNewObject:(id)sender
  {
      if (!_objects) {
          _objects = [[NSMutableArray alloc] init];
      }
      [_objects insertObject:[NSDate date] atIndex:0];
      NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
      [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
  }
  
  #pragma mark - Table View
  
  - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  {
      return 1;
  }
  
  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  {
      return menu.count;
  }
  
  // Customize the appearance of table view cells.
  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  {
      static NSString *CellIdentifier = @"Cell";
  
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
      if (cell == nil) {
          cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
      }
  
  
      // NSDate *object = _objects[indexPath.row];
      // cell.textLabel.text = [object description];
      cell.textLabel.text = [menu objectAtIndex:indexPath.row];
      return cell;
  }
  
  - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
  {
      // Return NO if you do not want the specified item to be editable.
      return YES;
  }
  
  - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
  {
      if (editingStyle == UITableViewCellEditingStyleDelete) {
          [_objects removeObjectAtIndex:indexPath.row];
          [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
      } else if (editingStyle == UITableViewCellEditingStyleInsert) {
          // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
      }
  }
  
  /*
  // Override to support rearranging the table view.
  - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
  {
  }
  */
  
  /*
  // Override to support conditional rearranging of the table view.
  - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
  {
      // Return NO if you do not want the item to be re-orderable.
      return YES;
  }
  */
  
  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  {
      // NSDate *object = _objects[indexPath.row];
      // self.detailViewController.detailItem = object;
  
      // KFBDetailViewController *detailViewController = (KFBDetailViewController*)self.splitViewController.delegate;
  
      // UIViewController &lt;SubstitutableDetailViewController&gt; *detailViewController = nil;
  
      if (indexPath.row == 1)
      {
          // [((UINavigationController *)[self.splitViewController.viewControllers lastObject]) pushViewController:[[ListViewController alloc]initWithStyle:UITableViewStylePlain] animated:YES];
          // [[self.splitViewController.viewControllers lastObject] pushViewController:[[ListViewController alloc]initWithStyle:UITableViewStylePlain] animated:YES];
  
          // ListViewController *publicAffairs = [[ListViewController alloc] initWithNibName:nil bundle:[NSBundle  mainBundle]];
          // [self.navigationController pushViewController:publicAffairs animated:YES];
  
          ListViewController *publicAffairs = [[ListViewController alloc]initWithStyle:UITableViewStylePlain];
          WebViewController *wvc = [[WebViewController alloc]init];
          [publicAffairs setWebViewController:wvc];
          publicAffairs.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
          [self.navigationController pushViewController:publicAffairs animated:YES];
          // [self presentViewController:publicAffairs animated:YES completion:nil];
      }
      else if (indexPath.row == 9)
      {
          // [((UINavigationController *)[self.splitViewController.viewControllers lastObject]) pushViewController:[[SocialNetworks alloc]initWithNibName:@"SocialNetworks" bundle:nil] animated:YES];
          // [[self.splitViewController.viewControllers lastObject] pushViewController:[[SocialNetworks alloc]initWithNibName:@"SocialNetworks" bundle:nil] animated:YES];
  
          SocialNetworks *social = [[SocialNetworks alloc] initWithNibName:@"SocialNetworks" bundle:[NSBundle  mainBundle]];
          [self.navigationController pushViewController:social animated:YES];
      }
  }
  
  @end
  </code></pre>
  
  <p>DetailViewController:</p>
  
  <pre><code>#import "KFBDetailViewController.h"
  
  @interface KFBDetailViewController ()
  @property (strong, nonatomic) UIPopoverController *masterPopoverController;
  - (void)configureView;
  @end
  
  @implementation KFBDetailViewController
  
  #pragma mark - Managing the detail item
  
  - (void)setDetailItem:(id)newDetailItem
  {
      if (_detailItem != newDetailItem) {
          _detailItem = newDetailItem;
  
          // Update the view.
          [self configureView];
      }
  
      if (self.masterPopoverController != nil) {
          [self.masterPopoverController dismissPopoverAnimated:YES];
      }        
  }
  
  - (void)configureView
  {
      // Update the user interface for the detail item.
  
      if (self.detailItem) {
          self.detailDescriptionLabel.text = [self.detailItem description];
      }
  }
  
  - (void)viewDidLoad
  {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
      [self configureView];
  }
  
  - (void)didReceiveMemoryWarning
  {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
  }
  
  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  {
      self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
      if (self) {
          self.title = NSLocalizedString(@"Detail", @"Detail");
      }
      return self;
  }
  
  #pragma mark - Split view
  
  - (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
  {
      barButtonItem.title = NSLocalizedString(@"Master", @"Master");
      [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
      self.masterPopoverController = popoverController;
  }
  
  - (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
  {
      // Called when the view is shown again in the split view, invalidating the button and popover controller.
      [self.navigationItem setLeftBarButtonItem:nil animated:YES];
      self.masterPopoverController = nil;
  }
  
  @end
  </code></pre>
  
  <p>ListViewController:</p>
  
  <pre><code>#import "ListViewController.h"
  #import "RSSChannel.h"
  #import "RSSItem.h"
  #import "WebViewController.h"
  #import "KFBDetailViewController.h"
  // #import "CustomCellBackground.h"
  
  @implementation ListViewController
  {
      UIActivityIndicatorView *loadingIndicator;
  }
  @synthesize webViewController;
  
  - (void)viewDidLoad
  {
  
      self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
      self.title = @"Public Affairs";
      loadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
      loadingIndicator.center = CGPointMake(160, 160);
      loadingIndicator.hidesWhenStopped = YES;
      [self.view addSubview:loadingIndicator];
      [loadingIndicator startAnimating];
      // UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
      // refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
      // [refresh addTarget:self action:@selector(refreshView:)forControlEvents:UIControlEventValueChanged];
      // self.refreshControl = refresh;
  }
  
  - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
  {
      if ([elementName isEqual:@"channel"])
      {
          // If the parser saw a channel, create new instance, store in our ivar
          channel = [[RSSChannel alloc]init];
  
          // Give the channel object a pointer back to ourselves for later
          [channel setParentParserDelegate:self];
  
          // Set the parser's delegate to the channel object
          [parser setDelegate:channel];
      }
  }
  
  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  {
      // return 0;
      NSLog(@"channel items %d", [[channel items]count]);
      return [[channel items]count];
  }
  
  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  {
      // return nil;
  
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
      if (cell == nil)
      {
          cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
          cell.textLabel.font=[UIFont systemFontOfSize:16.0];
      }
      RSSItem *item = [[channel items]objectAtIndex:[indexPath row]];
  
      // cell.backgroundView = [[CustomCellBackground alloc] init];
      // cell.selectedBackgroundView = [[CustomCellBackground alloc] init];
      cell.textLabel.backgroundColor = [UIColor clearColor];
      cell.textLabel.highlightedTextColor = [UIColor darkGrayColor];
  
      if (item.isActionAlert) {
          NSLog(@"Action Alert...Not Using");
      }
      else
      {
          [[cell textLabel]setText:[item title]];
      }
  
      return cell;
  }
  
  - (void)fetchEntries
  {
      // Create a new data container for the stuff that comes back from the service
      xmlData = [[NSMutableData alloc]init];
  
      // Construct a URL that will ask the service for what you want -
      NSURL *url = [NSURL URLWithString:@"http://kyfbnewsroom.com/category/public-affairs/feed"];
  
      // Put that URL into an NSURLRequest
      NSURLRequest *req = [NSURLRequest requestWithURL:url];
  
      // Create a connection that will exchange this request for data from the URL
      connection = [[NSURLConnection alloc]initWithRequest:req delegate:self startImmediately:YES];
  }
  
  - (id)initWithStyle:(UITableViewStyle)style
  {
      self = [super initWithStyle:style];
  
      if (self)
      {
          [self fetchEntries];
      }
  
      return self;
  }
  
  // This method will be called several times as the data arrives
  - (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
  {
      // Add the incoming chunk of data to the container we are keeping
      // The data always comes in the correct order
      [xmlData appendData:data];
  }
  
  - (void)connectionDidFinishLoading:(NSURLConnection *)conn
  {
      /* We are just checking to make sure we are getting the XML
       NSString *xmlCheck = [[NSString alloc]initWithData:xmlData encoding:NSUTF8StringEncoding];
       NSLog(@"xmlCheck = %@", xmlCheck);*/
  
      [loadingIndicator stopAnimating];
  
      // Create the parser object with the data received from the web service
      NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
  
      // Give it a delegate
      [parser setDelegate:self];
  
      //Tell it to start parsing - the document will be parsed and the delegate of NSXMLParser will get all of its delegate messages sent to it before this line finishes execution - it is blocking
      [parser parse];
  
      // Get rid of the XML data as we no longer need it
      xmlData = nil;
  
      // Reload the table.. for now, the table will be empty
      NSMutableArray *actionAlerts = [NSMutableArray array];
      for (RSSItem *object in channel.items) {
          if (object.isActionAlert) {
              [actionAlerts addObject:object];
          }
      }
  
      for (RSSItem *object in actionAlerts) {
          [channel.items removeObject:object];
      }
      [[self tableView]reloadData];
  
      NSLog(@"%@\n %@\n %@\n", channel, [channel title], [channel infoString]);
  }
  
  - (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
  {
      // Release the connection object, we're done with it
      connection = nil;
  
      // Release the xmlData object, we're done with it
      xmlData = nil;
  
      // Grab the description of the error object passed to us
      NSString *errorString = [NSString stringWithFormat:@"Fetch failed: %@", [error localizedDescription]];
  
      // Create and show an alert view with this error displayed
      UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
      [av show];
  }
  
  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  {   
      [((UINavigationController *) [self.splitViewController.viewControllers lastObject]) pushViewController:webViewController animated:YES];
  
      // Grab the selected item
      RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
  
      NSLog(@"Channel Items: %@", [[channel items]objectAtIndex:[indexPath row]]);
  
      // Construct a URL with the link string of the item
      NSURL *url = [NSURL URLWithString:[entry link]];
  
      NSLog(@"Link: %@", [entry link]);
  
      // Construct a request object with that URL
      NSURLRequest *req = [NSURLRequest requestWithURL:url];
  
      NSLog(@"URL: %@", url);
  
      // Load the request into the web view
      [[webViewController webView]loadRequest:req];
      webViewController.hackyURL = url;
      NSLog(@"Request: %@", req);
  
      // Set the title of the web view controller's navigation item
      // [[webViewController navigationItem]setTitle:[entry title]];
  
      NSLog(@"Title: %@", [entry title]);
  }
  
  @end
  </code></pre>
  
  <p>AppDelegate:</p>
  
  <pre><code>- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
      self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
      // Override point for customization after application launch.
  
      KFBMasterViewController *masterViewController = [[KFBMasterViewController alloc] initWithNibName:@"KFBMasterViewController" bundle:nil];
      UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
  
      KFBDetailViewController *detailViewController = [[KFBDetailViewController alloc] initWithNibName:@"KFBDetailViewController" bundle:nil];
      UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
  
      masterViewController.detailViewController = detailViewController;
  
      self.splitViewController = [[UISplitViewController alloc] init];
      self.splitViewController.delegate = detailViewController;
      self.splitViewController.viewControllers = @[masterNavigationController, detailNavigationController];
      self.window.rootViewController = self.splitViewController;
      [self.window makeKeyAndVisible];
      return YES;
  }
  </code></pre>