경고 : 뷰가 창 계층 구조에없는 *에 *를 표시하려고합니다.


83

데이터 모델에 저장된 데이터가 ViewController 있는지 여부 를 제시하려고합니다 . 하지만 다음과 같은 오류가 발생합니다.

경고 : *보기가 창 계층 구조에없는 경우에 *를 표시하려고합니다. "

관련 코드 :

override func viewDidLoad() {
    super.viewDidLoad()
    loginButton.backgroundColor = UIColor.orangeColor()

    var request = NSFetchRequest(entityName: "UserData")
    request.returnsObjectsAsFaults = false

    var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context:NSManagedObjectContext = appDel.managedObjectContext!

    var results:NSArray = context.executeFetchRequest(request, error: nil)!

    if(results.count <= 0){
        print("Inga resultat")
    } else {
        print("SWITCH VIEW PLOX")
        let internVC = self.storyboard?.instantiateViewControllerWithIdentifier("internVC") as internViewController
        self.presentViewController(internVC, animated: true, completion: nil)
    }
}

Google을 사용하여 찾은 다른 솔루션을 성공하지 못했습니다.


Storyboard에서 ViewController를 연결 했습니까? 여기서 NavigationController를 사용하고 있습니까?
derdida 2014 년

ViewControllerStoryboard에서 연결했다면 무슨 의미 입니까? 내가 사용하고 있지 않다 NavigationController@derdida을
닐스 Wasell

시도 : ViewDidLoad의 self.addChildViewController (childController : UIViewController)
derdida

이로 인해 오류가 발생합니다. "유형 이름"( UIViewController부분) 뒤에 멤버 이름 또는 생성자 호출이 필요 합니다. @derdida
닐스 Wasell

어디서 썼어요? MainViewController의 ViewDidLoad에서?
derdida 2014 년

답변:


127

코드의이 시점에서 뷰 컨트롤러의 뷰는 생성되었을뿐 뷰 계층에 추가되지 않았습니다. 가능한 한 빨리 해당 뷰 컨트롤러에서 viewDidAppear프레젠테이션하려면 가장 안전 해야합니다 .


2
viewDidAppear에 넣으면 presentViewController를 닫으면 다시 viewDidAppear 메서드를 호출하고 viewController를 다시 표시합니다. 제시하기 전에 조건문을 넣는 해결 방법이 있지만 대신 방법이 있습니까? 조건문?
Puneet 2014

2
화면이 나타날 때 바로 다른 모달을 제시하려는 것은 시작하기에 이상한 동작이므로 상태 bool은 최악의 솔루션이 아닙니다. 동시에 모달을 표시해야하는 근본 이유를 생각하고 해당 정보에 액세스 할 수 있는지 확인하십시오.
Acey 2014

2
viewWillAppear에서 수행하면 프레젠테이션을 시작할 때 프레젠테이션 중간에있는 상황이 발생합니다. 대안은 viewWillAppear에 넣지 만 iOS 8의 새로운 transitionCoordinator 속성을 사용하여 전환 완료시 코드를 추가하는 것입니다. 더 많은 정보는 여기에서 찾을 수 있습니다. developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Acey

36

객관적인 C에서 : 이것은 mpmovieplayer 위에 viewcontroller를 표시 할 때 내 문제를 해결했습니다.

- (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

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

    return topController;
}

34

스위프트 3

나는 이것을 초보자로 계속해서 올렸고 현재는 무시할 수있는 모달 뷰를로드하지만 모달을 표시 할 필요가없는 경우 루트 컨트롤러로 전환하는 것이 가장 좋습니다.

나는 이것을 사용하고 있었다

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc  = storyboard?.instantiateViewController(withIdentifier: "MainAppStoryboard") as! TabbarController
present(vc, animated: false, completion: nil)

내 tabController와 함께 대신 이것을 사용하십시오.

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let view = storyboard.instantiateViewController(withIdentifier: "MainAppStoryboard") as UIViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//show window
appDelegate.window?.rootViewController = view

여러 스토리 보드 화면간에 전환해야하는 경우보기 컨트롤러로 조정하면됩니다.


16

스위프트 3.

이 함수를 호출하여 최상위 뷰 컨트롤러를 가져온 다음 해당 뷰 컨트롤러를 제공합니다.

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
        while (topController.presentedViewController != nil) {
            topController = topController.presentedViewController!
        }
        return topController
    }

용법:

let topVC = topMostController()
let vcToPresent = self.storyboard!.instantiateViewController(withIdentifier: "YourVCStoryboardID") as! YourViewController
topVC.present(vcToPresent, animated: true, completion: nil)

1
고맙습니다 @Jacob Davis for this! 현재까지 시도 .... : 나는 내가 경고를 받고 한 원인 alertController 표시하는 데 사용
게리 Mansted을

이것은 매우 유용합니다. 일부 컨트롤러를 제시하고 있지만 화면이 나타나지 않습니다. 갑자기 해산됩니다. 다른 코드를 구현해야합니까? 제안하십시오
Seethalakshmi_user8943692

13

SWIFT 용

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
감사합니다! 이것이 나를 위해이 오류를 해결 한 유일한 방법이었습니다. 뷰가 완전히로드 된 후 (Xcode 8 / iOS 10에서) 제스처 인식기에 의해 트리거 된 기능에서 모달 VC를 제시하려고했습니다. 이상하게 topController도이 함수에 의해 반환 된 것은을 self사용하여 직접 제시하려고 할 때 와 똑같은 VC self.presentViewController(myModalVC)이지만 함수를 사용하여 제시 VC를 전달할 때 뷰 계층 구조 오류가 없습니다.
Natalia

13

지연 시간이있는 선택기를 수행하면됩니다 (0 초 작동).

override func viewDidLoad() {
    super.viewDidLoad()
    perform(#selector(presentExampleController), with: nil, afterDelay: 0)
}

@objc private func presentExampleController() {
    let exampleStoryboard = UIStoryboard(named: "example", bundle: nil)
    let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleVC") as! ExampleVC
    present(exampleVC, animated: true) 
}

감사합니다. 나는이 문제에 한 시간 넘게 갇혀 있었다.
Reza

감사 ... @objc FUNC presentExampleController ()
윌리엄 초이

놀라운 대답이라고 생각합니다!
mazend

이것은 해킹 (지금 작동 할 수 있음)이지만 예상치 못한 경우에 중단되는 무언가에 대비할 것입니다.
William Grand

6

스위프트 4

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
에 대한 설명 및 예는 도움이 @AllenWixted 것
유리 페레즈 벨트레

2

신속한 3.0 이상

public static func getTopViewController() -> UIViewController?{
if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
  return topController
}
return nil}

2

사용자가 딥 링크를 연 후 컨트롤러를 표시하는 동안이 오류가 발생했습니다. 이것이 최선의 해결책이 아니라는 것을 알고 있지만 짧은 시간 내에 여기에 빠른 수정이 있습니다. 코드를 asyncAfter다음 과 같이 감싸십시오 .

DispatchQueue.main.asyncAfter(deadline: .now() + 0.7, execute: { [weak self] in
                                navigationController.present(signInCoordinator.baseController, animated: animated, completion: completion)
                            })

발표하는 컨트롤러가을 (를) 호출 할 시간을줍니다 viewDidAppear.


1
let storyboard = UIStoryboard(name: "test", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "teststoryboard") as UIViewController
UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true, completion: nil)

이것은 그것이 가장 높은 뷰인지 확인하기 위해 작동하는 것처럼 보였습니다.

오류가 발생했습니다

경고 : myapp.testController : 0x7fdd01703990을 myapp.testController : 0x7fdd01703690에 표시하려고합니다. 그 뷰는 창 계층 구조에 없습니다!

이것이 신속한 3으로 다른 사람들에게 도움이되기를 바랍니다.


1

나는 너무 많은 접근을 시도했다! 유일하게 유용한 것은 다음과 같습니다.

if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
}

1

당신이있을 때 여기 topViewController에 대한 모든 구현은 완전히 사례를 지원하지 않는 UINavigationController또는 UITabBarController그 두 당신이 조금 다른 취급을 필요로 들어 :

에 대한 UITabBarControllerUINavigationController는 다른 구현이 필요합니다.

다음은 topMostViewController를 얻는 데 사용하는 코드입니다.

protocol TopUIViewController {
    func topUIViewController() -> UIViewController?
}

extension UIWindow : TopUIViewController {
    func topUIViewController() -> UIViewController? {
        if let rootViewController = self.rootViewController {
            return self.recursiveTopUIViewController(from: rootViewController)
        }

        return nil
    }

    private func recursiveTopUIViewController(from: UIViewController?) -> UIViewController? {
        if let topVC = from?.topUIViewController() { return recursiveTopUIViewController(from: topVC) ?? from }
        return from
    }
}

extension UIViewController : TopUIViewController {
    @objc open func topUIViewController() -> UIViewController? {
        return self.presentedViewController
    }
}

extension UINavigationController {
    override open func topUIViewController() -> UIViewController? {
        return self.visibleViewController
    }
}

extension UITabBarController {
    override open func topUIViewController() -> UIViewController? {
        return self.selectedViewController ?? presentedViewController
    }
}

1

이전 답변은 뷰를 표시해야하는 뷰 컨트롤러가 아직 뷰 계층 구조에 추가되지 않았거나 2) 상위 뷰 컨트롤러가 아닌 상황과 관련이 있습니다.
또 다른 가능성은 다른 경고가 이미 표시되었지만 아직 해제되지 않은 상태에서 경고가 표시되어야한다는 것입니다.


1

Swift Method를 사용하고 데모를 제공합니다.

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

func demo() {
    let vc = ViewController()
    let nav = UINavigationController.init(rootViewController: vc)
    topMostController().present(nav, animated: true, completion: nil)
}

1

Swift 5.1 :

let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let mainViewController = storyboard.instantiateViewController(withIdentifier: "ID")
let appDeleg = UIApplication.shared.delegate as! AppDelegate
let root = appDeleg.window?.rootViewController as! UINavigationController
root.pushViewController(mainViewController, animated: true)

1

메인 스레드를 사용하여 뷰 컨트롤러를 표시하고 해제했습니다.

DispatchQueue.main.async { self.present(viewController, animated: true, completion: nil) }

0

상위 뷰 컨트롤러를 찾는 대신

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

viewController가 표시하려는 컨트롤러 인 경우 TabBar, NavBar와 같은 계층 구조에 다른 종류의 뷰가있을 때 유용합니다. 다른 것들은 정확 해 보이지만 좀 더 hackish

다른 프레젠테이션 스타일은 apple doc 에서 찾을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.