iOS Split View Showing Detail in Master leaving Detail Blank

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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

 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,155
453
Harrogate
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.
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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
 
Last edited:

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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
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..
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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?
 

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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 ^_-
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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 ^_-
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.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,155
453
Harrogate
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.
 
Last edited:

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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.
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.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,155
453
Harrogate
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?
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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?
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.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,155
453
Harrogate
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?
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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?
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?
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,155
453
Harrogate
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.
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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.
I have relied heavily on ib in past. How would I make sure it is linked up programmatically?
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,155
453
Harrogate
I have relied heavily on ib in past. How would I make sure it is linked up programmatically?
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.
 

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
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.
 

jbbenni

macrumors newbie
Dec 1, 2011
7
0
In IB with iOS 5 Storyboard ...

I have relied heavily on ib in past. How would I make sure it is linked up programmatically?
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.