警告:尝试在TabBarController上显示ViewController,其视图不在窗口层次结构中

时间:2014-07-31 09:46:15

标签: ios objective-c xcode5 segue

我知道这是一个常见问题,但似乎无法找到符合我需求的正确解决方案。

好的,我有一个 UIViewController (哪个父视图是 UINavigationController ,然后是 UITabBarController )被强制进入肖像模式。这个人能够以模态方式呈现另一个 UIViewController ,当用户旋转设备时,该 UIViewController 被强制保持在横向模式。我决定用一个手动的segue来介绍这个最后一个人。 以下是演示文稿的代码:

- (void)viewDidAppear:(BOOL)animated {
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self   selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void)orientationChanged:(NSNotification *)notification {
    // Respond to changes in device orientation
    if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation])) {
        [self performSegueWithIdentifier:@"gallerySegue" sender:self];
    }
}

-(void) viewDidDisappear {
    // Request to stop receiving accelerometer events and turn off accelerometer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}

要返回第一个视图控制器,我使用这些代码

- (void)viewDidAppear:(BOOL)animated {
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(returnBack:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

-(void) viewDidDisappear {
    // Request to stop receiving accelerometer events and turn off accelerometer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}

- (void)returnBack:(NSNotification *)notification {
    // Respond to changes in device orientation
    if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
        [self dismissViewControllerAnimated:NO completion:nil];
    }
}

当我旋转设备时,第二个视图控制器会生成警告

WHY ??

由于

3 个答案:

答案 0 :(得分:1)

Warning: Attempt to present ViewController on TabBarController whose view is not in the window hierarchy。此警告是因为当您从viewController中push:present: viewController时不在视图中。含义您的第一个视图控制器尚未加载或完全显示,但是您正在呈现或推送另一个视图控制器。

答案 1 :(得分:0)

解决!

而不是这个

  - (void)viewDidAppear:(BOOL)animated {
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self   selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

我将上面的代码放在viewWillAppear中。

关于这个

-(void) viewDidDisappear {
    // Request to stop receiving accelerometer events and turn off accelerometer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}

我将它放在prepareForSegue方法中并且有效!

答案 2 :(得分:0)

我是一位快速用户,但我认为在这里值得一提:

如果您尝试在viewDidLoad()上执行UI任务,则会收到此消息,因为您正在执行的所有任务都将加载到内存中,但在正确加载视图层次结构之前无法执行任何操作。只是您在尝试查看层次结构之前正在尝试做某事。

因此,解决方案是等待几秒钟,直到正确加载视图层次结构。这是不建议使用的方法(也将在显示视图后执行),但我需要向您展示您也可以执行以下操作:

override func viewDidLoad() {
    super.viewDidLoad()
    //your stuff....
    Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(doSomeStuff), userInfo: nil, repeats: false)
}

@objc func doSomeStuff() {
    //your stuff....
    self.performSegue(withIdentifier: "signInTabBarVC", sender: nil) // i just want to perform transition if logged in
}

正如我所说的那样,不建议这样做,这是建议的方法:

override func viewDidAppear(_ animated: Bool) {
    //if Auth.auth().currentUser != nil {
        self.performSegue(withIdentifier: "signInTabBarVC", sender: nil)
    //}
}

上面是override方法,苹果公司推荐该方法执行UI任务。因为它是在视图层次结构初始化并附加后执行的。