问题
Well, might not be clear with the title. I have pulled this right out of the MultipleDetailView sample code from Apple. Every time the user selects a row from the table in the pop over, detailViewController is allocated the FirstDetailViewController and SecondDetailViewController again. Instead of allocating and initializing the view controller over and over, I want to assign the existing and already allocated and initialized view controller if existing to the detailViewController on the selection of the row. I have modified the Split View Template instead of the sample code to achieve what I need. Code from the program:
This is the AppDelegate.h file:
@interface iPadHelloWorldAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UISplitViewController *splitViewController;
MasterViewController *masterViewController;
DetailViewController *detailViewController;
SecondDetailViewController *secondDetailViewController;
}
This is the AppDelegate.m file:
masterViewController = [[MasterViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailView" bundle:nil];
secondDetailViewController = [[SecondDetailViewController alloc] initWithNibName:@"SecondDetailView" bundle:nil];
splitViewController = [[UISplitViewController alloc] init];
splitViewController.viewControllers = [NSArray arrayWithObjects:navigationController, detailViewController, nil];
splitViewController.delegate = detailViewController;
// Add the split view controller's view to the window and display.
[window addSubview:splitViewController.view];
[window makeKeyAndVisible];
This is the MasterViewController.m:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = indexPath.row;
[self.appDelegate.splitViewController viewWillDisappear:YES];
self.tempArrays = [NSMutableArray arrayWithArray:self.appDelegate.splitViewController.viewControllers];
[self.tempArrays removeLastObject];
if (row == 0) {
[self.tempArrays addObject:self.appDelegate.detailViewController];
self.appDelegate.splitViewController.delegate = self.appDelegate.detailViewController;
}
if (row == 1) {
[self.tempArrays addObject:self.appDelegate.secondDetailViewController];
self.appDelegate.splitViewController.delegate = self.appDelegate.secondDetailViewController;
}
self.appDelegate.splitViewController.viewControllers = self.tempArrays;
[self.appDelegate.splitViewController viewWillAppear:YES];
}
This is the DetailViewController.m:
#pragma mark -
#pragma mark Split view support
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc {
barButtonItem.title = @"Master List";
[navigationBar.topItem setLeftBarButtonItem:barButtonItem animated:NO];
self.popoverController = pc;
}
// Called when the view is shown again in the split view, invalidating the button and popover controller.
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
[navigationBar.topItem setLeftBarButtonItem:nil animated:NO];
self.popoverController = nil;
}
I am able to lazy load the view controllers, but when I tap the bar button for the popover and jump to the second view controller, the second view controller does not show the pop over. When I jump back to the first detail view controller, the popover is displayed.
Basically, here is a similar question. But the link to the drop box there doesn't work.
回答1:
Since you have asked me to have shot - here it goes. The SplitViewController is rather buggy, from our opinion here. We have encountered many problems if you don't stick to exactly the way Apple does it in their sample code.
First of all, I would suggest you take the sample code again and start from scratch, since it seems you have modified a lot.
As for your problem: In your delegate and the MainWindow.xib you set up your SplitViewController. The most important thing is to not set up the viewControllers array the way you do it.
I encountered the problem that if I overwrite the RootViewController, it messes up the SplitViewController and produces bugs like the one you encounter.
Try setting up your RootViewController (the TableViewController) only once and never overwrite it in the viewControllers property. This seems to be OK for the DetailViewController, though.
Secondly, you code should be placed elsewhere, not in the RootViewController. This should be for the tableView datasource and content only.
Try this and feedback here, I'll follow asap.
Best of luck.
EDIT: code addition - do this in your RootViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
DetailViewController *dvC = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
// take the original view controller from the splitviewcontroller as root
// appDelegateiPad defined like this in my appdelegate:
// #define appDelegateiPad ((AppDelegate_iPad *)[[UIApplication sharedApplication] delegate])
NSArray *viewControllers = [[NSArray alloc] initWithObjects:[[appDelegateiPad.splitViewController viewControllers]objectAtIndex:0], dvC, nil];
appDelegateiPad.splitViewController.viewControllers = viewControllers;
//careful with this, set it to whatever your delegate is in your case
appDelegateiPad.splitViewController.delegate = dvC;
[viewControllers release];
//this is my version
//i have the popoverController property in my detailviewcontroller. this is where my splitviewcontroller delegate methods are. you need to set the popovercontroller property in the class where your splitviewcontroller delegate methos are
dvC.popoverController = [[[appDelegateiPad.splitViewController viewControllers]objectAtIndex:1] popoverController];
}
}
回答2:
Try allocating the viewControllers in the viewDidLoad in this object. Give both viewcontrollers a title and put them in an array. These titles you can use for both cells textlabels if needed. In the didSelectRowAtIndexPath you can get the correct viewcontroller for the selected row
UIViewController <SubstitutableDetailViewController> *detailViewController = [theArray objectAtIndex:indexPath.row];
Edit:
@interface SomeClass : NSObject {
NSArray *controllerArray;
}
@end
@implementation SomeClass
- (void) viewDidLoad {
controllerArray = [[NSArray alloc] initWithObject://yourControllers//,nil];
[super viewDidLoad]
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Two sections, one for each detail view controller.
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Create Cell
UIViewCOntroller *controller = [controllerArray objectAtIndex:indexPath.row];
cell.textLabel.text = controller.title;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[detailViewController autorelease];
detailViewController = [[controllerArray objectAtIndex:indexPath.row] retain];
}
@end
回答3:
It isn't necessary to create a new instance of the detail view controller or update the viewControllers in the split view controller.
Try this.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIApplication *application = [UIApplication sharedApplication];
AppDelegate *appDelegate = (AppDelegate*) [application delegate];
appDelegate.detailViewController.label.text = @"Detail view controller updated";
}
PS: Please, drag a label to the detail for testing.
来源:https://stackoverflow.com/questions/5014479/require-uisplitviewcontroller-to-lazy-load-multiple-view-controllers-for-detail