Split View Showing Detail in Master leaving Detail Blank

Discussion in 'iOS Programming' started by newtoiphonesdk, Nov 16, 2011.

  1. newtoiphonesdk macrumors 6502a

    Joined:
    Jul 30, 2010
    #1
    I have a master-detail application built that parses an RSS Feed. After compiling everything, it appears at first to work great. The feed items show in either the popover or master controller depending on portrait or landscape. When I select an article, it shows the article in the master controller and leaves the detail controller blank. Any ideas? Here are screenshots and code used. I removed some of the code from .m for parsing to get to the limit of characters.
    Here is Master.h
    Code:
    #import <UIKit/UIKit.h>
    @protocol MasterViewController <NSObject>
    
    -(void)didTap:(NSString *)string;
    
    @end
    id delegate;
    @class DetailViewController;
    
    @interface MasterViewController : UITableViewController {
        NSOperationQueue *_queue;
        NSArray *_feeds;
        NSMutableArray *_allEntries;
    }
    
    @property (strong, nonatomic) DetailViewController *detailViewController;
    @property (nonatomic, assign) id<MasterViewController> delegate;
    @property (retain) NSOperationQueue *queue;
    @property (retain) NSArray *feeds;
    @property (retain) NSMutableArray *allEntries;
    
    @end
    
    Master.m
    Code:
    #import "MasterViewController.h"
    
    #import "DetailViewController.h"
    #import "RSSEntry.h"
    #import "ASIHTTPRequest.h"
    #import "GDataXMLNode.h"
    #import "GDataXMLElement-Extras.h"
    #import "NSDate+InternetDateTime.h"
    #import "NSArray+Extras.h"
    @implementation MasterViewController
    
    @synthesize detailViewController = _detailViewController;
    @synthesize allEntries = _allEntries;
    @synthesize feeds = _feeds;
    @synthesize queue = _queue;
    @synthesize delegate;
    
    - (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)refresh {
        
        for (NSString *feed in _feeds) {
            NSURL *url = [NSURL URLWithString:feed];
            ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
            [request setDelegate:self];
            [_queue addOperation:request];
        }
        
    }							
    - (void)dealloc
    {	[delegate release];
    
        [_allEntries release];
        _allEntries = nil;
        [_queue release];
        _queue = nil;
        [_feeds release];
        _feeds = nil;
    
        [_detailViewController release];
        [super dealloc];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Release any cached data, images, etc that aren't in use.
    }
    
    #pragma mark - View lifecycle
    
    - (void)viewDidLoad {
        [super viewDidLoad];    
    	
        self.title = @"iPreacher";
    	
        self.allEntries = [NSMutableArray array];
        self.queue = [[[NSOperationQueue alloc] init] autorelease];
        self.feeds = [NSArray arrayWithObjects:@"http://316apps.com/ipreachersblog/feed/",
                      nil];    
    	
    	
        [self refresh];
    }
    
    
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        // Return YES for supported orientations
        return YES;
    }
    
    // Customize the number of sections in the table view.
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 1;
    }
    
    
    // Customize the number of rows in the table view.
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return [_allEntries 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:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
        }
        
        RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
        
        NSDateFormatter * dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
        [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
        [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
        NSString *articleDateString = [dateFormatter stringFromDate:entry.articleDate];
        
        cell.textLabel.text = entry.articleTitle;        
        cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ - %@", articleDateString, entry.blogTitle];
    	
        return cell;
    }
    
    
    
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (!self.detailViewController) {
            self.detailViewController = [[[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil] autorelease];
        }
        RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
        _detailViewController.entry = entry;
        [self.delegate didTap:[_allEntries objectAtIndex:indexPath.row]];
        [self.navigationController pushViewController:self.detailViewController animated:YES];
    }
    
    @end
    
    Detail.h
    Code:
    
    #import <UIKit/UIKit.h>
    @class RSSEntry;
    
    @interface DetailViewController : UIViewController <UISplitViewControllerDelegate> {
        UIWebView *_webView;
        RSSEntry *_entry;
    	IBOutlet UIActivityIndicatorView *activity;
    	NSTimer *timer;
    	NSString *currentURL;
    	
    }
    -(IBAction)action:(id)sender;
    -(IBAction)save;
    @property (retain) IBOutlet UIWebView *webView;
    @property (retain) RSSEntry *entry;
    @property (nonatomic, retain) UIActivityIndicatorView *activity;
    @property (nonatomic, retain) NSString *currentURL;
    
    
    @end
    
    detail.m
    Code:
    #import "DetailViewController.h"
    #import "RSSEntry.h"
    
    @interface DetailViewController ()
    @property (strong, nonatomic) UIPopoverController *masterPopoverController;
    - (void)configureView;
    @end
    
    @implementation DetailViewController
    
    
    @synthesize masterPopoverController = _masterPopoverController;
    @synthesize webView = _webView;
    @synthesize entry = _entry;
    @synthesize activity;
    @synthesize currentURL;
    - (void)dealloc
    {[currentURL release];
        [_entry release];
        _entry = nil;
        [_webView release];
        _webView = nil;
            [_masterPopoverController release];
        [super dealloc];
    }
    
    #pragma mark - Managing the detail item
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Release any cached data, images, etc that aren't in use.
    }
    
    #pragma mark - View lifecycle
    /*
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	// Do any additional setup after loading the view, typically from a nib.
        [self configureView];
    }
    */
    - (void)viewDidUnload
    {
        [super viewDidUnload];
        // Release any retained subviews of the main view.
        // e.g. self.myOutlet = nil;
    }
    
    - (void)viewWillAppear:(BOOL)animated {
        
        NSURL *url = [NSURL URLWithString:_entry.articleUrl];    
        [_webView loadRequest:[NSURLRequest requestWithURL:url]];
        self.title = @"iPreacher";
        
    	timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:@selector(tick) userInfo:nil repeats:YES];
        
    }
    -(void)tick {
    	if(!_webView.loading)
    		[activity stopAnimating];
    	else 
    		[activity startAnimating];
    	
    }
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        // Return YES for supported orientations
        return YES;
    }
    
    - (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
    
    [​IMG]
    [​IMG]
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    The very obvious answer is that in the last statement of

    Code:
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    in the master you do this:

    Code:
    [self.navigationController pushViewController:self.detailViewController animated:YES];
    
    Clearly this pushes the detail into the navigation controller of the master. Which is what you are seeing. So you see exactly what you'd expect given the code you've written.
     
  3. newtoiphonesdk, Nov 16, 2011
    Last edited: Nov 16, 2011

    newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #3
    Wow. Don't know how I missed that one. Well maybe. Had a baby Friday an must still be out of it. Forget driving drowsy. Shouldn't code drowsy.

    Update:
    Went back and looked over different samples and documentation, and all master-detail apps use that line of code
     
  4. jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #4
    Wrong, they use it to make a drilldown, what you want to do is set the detail to the right, if you PUSH something on your OWN viewcontroller, which is a navigationcontroller, you will create the same as an iPhone app. You need to tell your detailview, that you want to render the detail.
    It's not that hard, alot of examples are flying around..
     
  5. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #5
    Here is what I have changed so far. In .m
    Code:
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    if (_webViewController2 == nil) {
    			self.webViewController2 = [[[WebViewController2 alloc] initWithNibName:@"WebViewController2" bundle:nil] autorelease];
    		}
    		_webViewController2.detailItem = [_allEntries objectAtIndex:indexPath.row];
            
    			}
    }
    WebViewController2 .h
    Code:
    #import <UIKit/UIKit.h>
    
    @class RSSEntry;
    
    @interface WebViewController2 : UIViewController <UISplitViewControllerDelegate, UIPopoverControllerDelegate> {
        UIWebView *_webView;
        RSSEntry *_entry;
    	IBOutlet UIActivityIndicatorView *activity;
    	NSTimer *timer;
    	NSString *currentURL;
    	id detailItem;
            UIPopoverController *masterPopoverController;
    }
    -(IBAction)action:(id)sender;
    -(IBAction)save;
    @property (retain) IBOutlet UIWebView *webView;
    @property (retain) RSSEntry *entry;
    @property (nonatomic, retain) UIActivityIndicatorView *activity;
    @property (nonatomic, retain) NSString *currentURL;
    @property (nonatomic, retain) id detailItem;
    
    @end
    .m
    Code:
    #import "WebViewController2.h"
    #import "RSSEntry.h"
    #import "SHK.h"
    @interface WebViewController2 ()
    @property (strong, nonatomic) UIPopoverController *masterPopoverController;
    - (void)configureView;
    @end
    
    @implementation WebViewController2
    @synthesize webView = _webView;
    @synthesize entry = _entry;
    @synthesize activity;
    @synthesize currentURL;
    @synthesize detailItem=_detailItem;
    @synthesize masterPopoverController;
    
    - (void)setDetailItem:(id)newDetailItem
    {
        if (_detailItem != newDetailItem) {
            [_detailItem release]; 
            _detailItem = [newDetailItem retain]; 
            
            // Update the view.
            [self configureView];
        }
        
        if (self.masterPopoverController != nil) {
            [self.masterPopoverController dismissPopoverAnimated:YES];
        }        
    }
    - (void)configureView
    {
        // Update the user interface for the detail item.
        
        
            NSURL *url = [NSURL URLWithString:_entry.articleUrl];    
            [_webView loadRequest:[NSURLRequest requestWithURL:url]];
            self.title = @"iPreacher";
            
            timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:@selector(tick) userInfo:nil repeats:YES];    
    }
    
    It no longer shows the story in the master view, but nothing shows in the Detail View side. The xib is set to the class of WebViewController2, but nothing will load in it. Any thoughts?
     
  6. jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #6
    Tl;DR, in other words, don't wonna go over the whole code, put smaller blocks up please, what did u try, where did u set breakpoints, NSLog's, till where does it goes, warnings, all of that please. Otherwise debugging over an Internet Forum is hard ^_-
     
  7. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #7
    Just forget it then. I put in smallest blocks of code I could for only affected parts and can't really narrow it down any more than that.
     
  8. robbieduncan, Nov 18, 2011
    Last edited: Nov 18, 2011

    robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    How/where is the detailItem property set?

    Edit: OK I see where that is done. But I don't really understand the overall view hierarchy that you are trying to build here.
     
  9. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #9
    Just trying to go off a few tutorials I read but it seems 4.2 changed a lot with split views. I simply want an rss reader. Root view on left side shows table view listing of articles and web view controller2 on right side has web view to display selected article. That's the attempt anyway.
     
  10. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    OK, but how are you managing the connection between the two? I've never done any of this using xibs: I always just create everything in code. Where do you change the view in the detail of the split view controller?
     
  11. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #11
    In main window I expand the split view controller and I set te view controller class under it to web view controller 2. The root view I set class to root view controller. The table view shows up on left side, so that seems to be at least partially set up.
     
  12. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #12
    As I said I don't user Interface Builder so I cannot be sure but that does not seem to answer my question at all. How does the instance of the set class in the master talk to the instance in the detail? Does it have a reference to that instance?
     
  13. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #13
    In my master view header file
    Code:
    #import <UIKit/UIKit.h>
    @class WebViewController2;
    @protocol RootViewControllerDelegate <NSObject>
    
    -(void)didTap:(NSString *)string;
    
    @end
    id delegate;
    
    @class WebViewController2;
    
    @interface RootViewController : UITableViewController {
        NSOperationQueue *_queue;
        NSArray *_feeds;
        NSMutableArray *_allEntries;
      
    	WebViewController2 *_webViewController2;
    	
    	
    }
    
    @property (nonatomic, assign) id<RootViewControllerDelegate> delegate;
    @property (retain) NSOperationQueue *queue;
    @property (retain) NSArray *feeds;
    @property (retain) NSMutableArray *allEntries;
    @property (retain) WebViewController2 *webViewController2;
    
    Is the id delegate and protocol part of the code what you are asking about?
     
  14. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #14
    Perhaps: have you linked that to the actual instance in the view. I note that you create a new instance if that is not set. How do you expect that to work: the new instance is not being added to the split view so will not be visible anywhere. I think you are missing some very fundamental knowledge based on your code.
     
  15. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #15
    I have relied heavily on ib in past. How would I make sure it is linked up programmatically?
     
  16. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #16
    You would only do that if you create everything programatically. You need to link the two instances in IB somehow. As I said I don't know anything about that. Or when you create your new detail view set it as the detail in the split controller.
     
  17. newtoiphonesdk thread starter macrumors 6502a

    Joined:
    Jul 30, 2010
    #17
    I tried changing the didSelectRowAtIndexPath to:
    Code:
     RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
            NSURL *url = [NSURL URLWithString:entry.articleUrl];    
            [webViewController2.webView loadRequest:[NSURLRequest requestWithURL:url]];
    
    Then I added a NSLog to the WebViewController2 (DetailSide of SplitView) to get the URL absoluteString of the webview, and it came back null, so I just can't figure out how to get the two sides to talk to each other.
     
  18. jbbenni macrumors newbie

    Joined:
    Dec 1, 2011
    #18
    In IB with iOS 5 Storyboard ...

    If you prefer to work in IB, you can do this part of the setup in IB without writing code. Start with a Split-View project, and create a segway from the table item on the left (Master) to the scene you want to be the right (Detail).

    Here's the trick: After creating the segue, select the segue in IB and use the identity inspector. Change the segue's property to be Detail. (The default is to the same type as the source of the segue, but you want the opposite.)

    Hope this helps.
     

Share This Page