[ios] 보기가 창 계층 구조에없는 UIViewController에 UIViewController를 표시하려고 시도합니다.

Xcode 4.5를 사용하기 시작했고 콘솔 에서이 오류가 발생했습니다.

경고 :보기가 창 계층 구조에없는 <ViewController : 0x1ec3e000>에 <finishViewController : 0x1e56e0a0>을 (를) 표시하십시오!

뷰가 계속 표시되고 앱의 모든 것이 제대로 작동합니다. iOS 6의 새로운 기능입니까?

이것은 뷰 사이를 변경하는 데 사용하는 코드입니다.

UIStoryboard *storyboard = self.storyboard;
finishViewController *finished = 
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];

[self presentViewController:finished animated:NO completion:NULL];



답변

이 메소드를 어디에서 호출합니까? viewDidLoad메서드 내에서 모달 뷰 컨트롤러를 제시하려고하는데 문제가있었습니다 . 나를위한 해결책은이 호출을 viewDidAppear:메소드 로 옮기는 것이 었습니다 .

내 가정은 뷰 컨트롤러의 뷰가 있다는 것입니다 하지 합니다 (이로드 된 시점에서 윈도우의 뷰 계층에 viewDidLoad메시지가 전송), 그러나 그것은 이다 가 발표 된 후 윈도우 계층합니다 (경우에 viewDidAppear:메시지가 전송됩니다) .


주의

당신이를 호출 할 할 경우 presentViewController:animated:completion:viewDidAppear:모달 뷰 컨트롤러는 항상 제공되고, 이에 당신이 문제로 실행할 수를 때마다 뷰 컨트롤러의 뷰가 나타납니다 (어떤 의미!)과 모달 뷰 컨트롤러는 멀리 가지 않을 것되게되고, 그래서 .. .

어쩌면 이것이 모달 뷰 컨트롤러를 표시하기에 가장 좋은 장소가 아니거나, 또는 추가 뷰 상태를 유지해야하는 경우도 있는데,이를 통해 프리젠 테이션 뷰 컨트롤러가 모달 뷰 컨트롤러를 즉시 표시해야하는지 여부를 결정할 수 있습니다.


답변

또 다른 잠재적 인 원인 :

실수로 동일한 뷰 컨트롤러를 두 번 제시 할 때이 문제가 발생했습니다. (한 번 performSegueWithIdentifer:sender:버튼을 눌렀을 때 호출되었고, 세그가 버튼에 직접 연결된 상태에서 두 번째로 호출되었습니다).

효과적으로, 두 개의 segue가 동시에 발사되었고, 나는 오류가 발생했습니다. Attempt to present X on Y whose view is not in the window hierarchy!


답변

viewWillLayoutSubviewsviewDidLayoutSubviews(아이폰 OS가 5.0)이 목적을 위해 이용 될 수있다. viewDidAppear보다 먼저 호출됩니다.


답변

하위 뷰를 메인 뷰에 표시하려면 다음 코드를 사용하십시오

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController)
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];

메인 뷰에서 하위 뷰를 해제하려면 다음 코드를 사용하십시오

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController)
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];


답변

에서을 (를) 제시하려고 할 때도이 문제가 발생 UIViewController했습니다 viewDidLoad. James Bedford의 답변은 효과가 있었지만 내 앱은 1 ~ 2 초 동안 배경을 먼저 보여주었습니다.

약간의 연구 끝에,를 사용하여 이것을 해결할 수있는 방법을 찾았습니다 addChildViewController.

- (void)viewDidLoad
{
    ...
    [self.view addSubview: navigationViewController.view];
    [self addChildViewController: navigationViewController];
    ...
}


답변

아마 나처럼 너는 틀린 뿌리를 가지고있어 viewController

나는를 표시 할 ViewControllerA의 non-UIViewController컨텍스트

그래서 나는 그런 코드를 사용할 수 없습니다 :

[self presentViewController:]

그래서 UIViewController를 얻습니다.

[[[[UIApplication sharedApplication] delegate] window] rootViewController]

어떤 이유로 (논리적 버그) rootViewController는 예상 이외의 것입니다 (정상 UIViewController). 그럼, 버그를 수정 교체 rootViewController로모그래퍼 UINavigationController하고 문제가 사라입니다.


답변

TL; DR 1 개의 rootViewController와 가장 최근에 표시된 것만 가질 수 있습니다. 따라서 뷰 컨트롤러가 이미 닫히지 않은 뷰 컨트롤러를 제공 할 때 다른 뷰 컨트롤러를 제시하려고 시도하지 마십시오.

내 자신의 테스트 중 일부를 수행 한 후 결론에 도달했습니다.

모든 것을 제시하려는 rootViewController가 있으면이 문제가 발생할 수 있습니다.

여기 내 rootController 코드가 있습니다 (open은 루트에서 viewcontroller를 표시하는 바로 가기입니다).

func open(controller:UIViewController)
{
    if (Context.ROOTWINDOW.rootViewController == nil)
    {
        Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
        Context.ROOTWINDOW.makeKeyAndVisible()
    }

    ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}

(시간 경과에 관계없이) 연속으로 두 번 open을 호출하면 첫 번째 열림에서는 잘 작동하지만 두 번째 열림에서는 잘 작동하지 않습니다. 두 번째 열린 시도는 위의 오류를 발생시킵니다.

그러나 가장 최근에 표시된보기를 닫은 다음 open open을 사용하면 (다른 viewcontroller에서) open을 다시 호출하면 정상적으로 작동합니다.

func close(controller:UIViewController)
{
    ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}

내가 결론을 내린 것은 MOST-RECENT-CALL만의 rootViewController가 뷰 계층에 있다는 것입니다 (뷰를 닫지 않았거나 뷰를 제거하지 않더라도). 모든 로더 호출 (viewDidLoad, viewDidAppear 및 지연 된 디스패치 호출 수행)을 사용하여 시도했지만 작동시킬 수있는 유일한 방법은 최상위 뷰 컨트롤러에서만 present를 호출하는 것입니다.