Determine frame/bounds in viewDidLoad

2020-03-31 06:27发布

Hello fellow programmers,

First, sorry for the long post. My question is rather simple, but I want to make sure you know what I'm doing and I really don't want to change the basic idea of my approach.

(the following is all done programmatically, no storyboards, no nibs, no navigationcontroller)

I have a RootViewController without an own view. All he does is instantiate other ViewControllers, manage their transitions and push (add) their views into the main window. To position these views correctly, I want to get bounds/frame for one of the RootViewCOntrollers SubControllers. This is how I create the RootViewController from the appDelegate (I started with a empty project)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor grayColor];
    self.window.rootViewController = [[UCRootViewController alloc]init];
    [self.window makeKeyAndVisible];
    return YES;
}

After his initialization, the rootviewController creates a MapViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"RootviewController initialized");
    self.mapviewController = [[UCMapviewController alloc] initWithDelegate:self];
    self.view = self.mapviewController.view;
    [self.mapviewController.view setOpaque:YES];
    [self.view bringSubviewToFront:self.mapviewController.view];
    [self presentModalViewController:self.mapviewController animated:YES];
    self.currentlyActiveController = self.mapviewController;
}

The MapViewController creates a navigationBar and a MKMapView. Right now I set the frames hardcoded, because I'm not able to get the bounds/frame of the window in the viewDidLoad() of the MapViewController When I try to get any infos about bounds/frame, I get 0 returned.

- (void)viewDidLoad
{
    NSLog(@"MapviewController initialized");
    [super viewDidLoad];

    self.isMapViewPushedAside = NO;
    // Custom initizialation for navigationBar
    [self setupNavigationBar];

    // Custom initialization for mapview
    [self setUpMapview];
    [self trackUserLocation];

    // Custom initialization for popupActionsButton
    [self setUpPopupButtons];

    // Custom tests
    [self test];

    [self focusLocationOnMap:self.locationManager.location.coordinate];
    [self.locationManager stopUpdatingLocation];
}

I've implemented two delegate methods that return frame/bounds (same) for the window. The problem is, I must get those values at the start, not after everything has been initialized. when I call the delegate methods from a button after everything is up, they work as expected.

CGRect frame = [self.mapDelegate frameData];
NSLog(@"width by frame: %f", frame.size.width);
NSLog(@"height by frame: %f", frame.size.height);

CGRect bounds = [self.mapDelegate boundsData];
NSLog(@"width by bounds: %f", bounds.size.width);
NSLog(@"height by bounds: %f", bounds.size.height);

How do I obtain the frame/bounds at the start, that is, before calling my custom "setup" methods..?!

1条回答
Juvenile、少年°
2楼-- · 2020-03-31 06:29

I have a RootViewController without an own view.

You can't have a UIViewController without a view. If you have the app will crash. When you initialize a UIViewController it automatically creates a UIView for you.

- (void)viewDidLoad
{
    [super viewDidLoad];
    ..
    self.mapviewController = [[UCMapviewController alloc] initWithDelegate:self];
    self.view = self.mapviewController.view;
    ..
}

From what can I see here, you're actually setting the RootviewController's view to be the map view. This should be done by overriding the -(void)loadView method of your controller and there you need to set the view:

-(void)loadView
{
    self.mapviewController = [[UCMapviewController alloc] initWithDelegate:self]; //if you're not using ARC this should be autoreleased;
    self.view = self.mapviewController.view;
}

When viewDidLoad method is called there is no geometry set in any of the views of your controller. They are only initialized (implicitly or explicitly by -(void)loadView) and viewDidLoad is called just right after that. Geometry is setup at earliest in viewWillAppear: method and the consecutive viewDidAppear: method, so viewWillAppear: is the earliest point you can have your actual frame/bounds of your views and in viewWillAppear: method you should only execute some lightweight operations (like setting geometry, starting timers, subscribe observers, etc..).
You said you don't want to change your approach, but you need to design according to these rules.

查看更多
登录 后发表回答