why does this different “addSubView” code cause di

2019-03-27 07:25发布

问题:

Why does changing the below code from the Old to New entry fix the following problem.

Code:

  // OLD Entry - Did not work
  //[self.window addSubview:navigationController.view];

  // NEW Entry - Fixed it
  self.window.rootViewController = self.navigationController;

Problem when I use Old Code:

  • I'm using a UINavigationController and have a "mainView" UITableViewController and then a 2nd level view I push onto the stack, let's call it "detailedView" UITableViewController.

  • Navigating normally back and forward from main to details works fine

  • BUT when automatically launch on startup into the 2nd view (as I save state) I get to the 2nd view OK, however the TOOLBAR BUTTONS do NOT appear at the bottom of the 2nd view in this case. When I go back to main page (via UINavigationController standard arrangements), and then then select the row in the UITableView, and go back into the same view again the toolbar items appear fine.

  • Couldn't track this down but finally through trial and error I noted this change in code (see above) in the appDelegate (of all places) seems to fix the issue.

Any ideas?

EDIT: For completeness here is the full method

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
    NSManagedObjectContext *context = [self managedObjectContext];
    if (!context) {
        abort();  // TODO: Do better job here than abort
    }
    rootViewController.managedObjectContext = context;
     self.window.rootViewController = self.navigationController;
    [self.window makeKeyAndVisible];
    return YES;
}

EDIT 2: Oh, I do have a NIB file and have the root view controller/window setup in interface builder - so I'm wondering if I'm mixing a NIB and programmatic approach up here perhaps which might cause problems?

EDIT 3: Also noted that the following didFinishLaunchingWithOptions code worked when I added the "self.window.rootViewController = self.navigationController" line. That is without this line (which is what the coredatabooks example does) I get the issue.

RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
    rootViewController.managedObjectContext = self.managedObjectContext;
    self.window.rootViewController = self.navigationController;  // WORKS WHEN I ADD THIS LINE IN FOR SOME REASON???

    // Configure and show the window
    [window addSubview:[navigationController view]];
    [window makeKeyAndVisible];

return YES;

回答1:

The difference between the two methods is that one triggers the view lifecycle methods the other dose not.

I.e. setting window.rootViewController will cause the old view controller to receive the messages: viewDidDissaper viewWillDissapear etc.. while the new view controller will receive the viewWillApear, viewDidAppear etc..

addSubview: does not do this.

Does this help?

EDIT:

Reading your post in detail it looks like you are adding the buttons programatically on the viewDidAppear method of the detail view.

The rootViewController property of UIWindow was added as of 4.0. The documentation does not explicitly mention that it will trigger the view life cycle methods, i found this out through trail and error like yourself. (perhaps someone can raise an issue against the apple documentation).

If you need to be backwards compatible for 3.x you can this a custom UIWindow subclass. My code is below. use window.djRootViewController = yourViewController instead of window.rootViewController. It is designed for use in Interface builder.

#import <UIKit/UIKit.h>

@interface DJWindow : UIWindow {

    UINavigationController* m_navigationController;
}

@property (nonatomic, retain) UIViewController* djRootViewController;

@end




#import "DJWindow.h"

@interface DJWindow()

- (void) customInit;

@end


@implementation DJWindow


- (id) initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        [self customInit];
    }
    return self;
}


- (void) customInit {
    m_navigationController = [[UINavigationController alloc] init];

    m_navigationController.navigationBarHidden = YES;

    [self addSubview:m_navigationController.view];
}

- (void) setRootViewController:(UIViewController *)rootViewController {
    NSLog(@"ERROR, do not set the rootViewController property, use djRootViewController instead");
}

- (void) setDjRootViewController:(UIViewController *)djRootViewController {

    if (djRootViewController == nil) {
        [m_navigationController setViewControllers:nil];
    } else {
        NSArray* vcArray = [NSArray arrayWithObject:djRootViewController];
        [m_navigationController setViewControllers:vcArray];
    }
}

- (UIViewController*) djRootViewController {

    return m_navigationController.visibleViewController;
}

- (void)dealloc
{
    [m_navigationController release];
    [super dealloc];
}


@end