Cảnh báo: Cố gắng hiển thị * bật * có chế độ xem không nằm trong phân cấp cửa sổ - nhanh chóng


83

Tôi đang cố gắng trình bày ViewController nếu có bất kỳ dữ liệu đã lưu nào trong mô hình dữ liệu. Nhưng tôi gặp lỗi sau:

Cảnh báo: Cố gắng hiển thị * trên * mà chế độ xem không nằm trong phân cấp cửa sổ "

Mã liên quan:

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)
    }
}

Tôi đã thử các giải pháp khác nhau được tìm thấy bằng Google mà không thành công.


Bạn đã kết nối ViewController của mình trong Storyboard chưa? Bạn đang sử dụng NavigationController ở đây?
derdida

Ý bạn là gì nếu tôi đã kết nối của mình ViewControllertrong Storyboard? Tôi không sử dụng NavigationController@derdida
Nils Wasell

Hãy thử: self.addChildViewController (childController: UIViewController) trong viewDidLoad
derdida

Điều này tạo ra một lỗi. Nó mong đợi một tên thành viên hoặc một cuộc gọi hàm tạo sau "tên kiểu" (Phần UIViewController). @derdida
Nils Wasell,

Bạn đã viết cái đó ở đâu? Trong ViewDidLoad của MainViewController của bạn?
derdida

Câu trả lời:


126

Tại thời điểm này trong mã của bạn, chế độ xem của bộ điều khiển chế độ xem chỉ mới được tạo nhưng chưa được thêm vào bất kỳ phân cấp chế độ xem nào. Nếu bạn muốn trình bày từ bộ điều khiển chế độ xem đó càng sớm càng tốt, bạn nên làm điều đó viewDidAppearđể an toàn nhất.


2
Nếu tôi đặt nó trong viewDidAppear, thì khi tôi loại bỏ PresentViewController, nó sẽ gọi lại phương thức viewDidAppear và trình bày lại viewController. Tôi có một giải pháp là đặt một câu lệnh điều kiện trước khi trình bày nó, nhưng có cách nào thay vì đặt một câu lệnh điều kiện?
Puneet

2
Tôi có thể nói rằng cố gắng trình bày một phương thức khác ngay khi màn hình xuất hiện là một hành vi kỳ quặc để bắt đầu, vì vậy bool trạng thái hầu như không phải là giải pháp tồi tệ nhất. Đồng thời, hãy nghĩ về lý do gốc rễ mà bạn cần hiển thị phương thức và xem liệu bạn có thể truy cập thông tin đó hay không.
Acey

2
Nếu bạn làm điều đó trong viewWillAppear, bạn sẽ gặp trường hợp đang trình bày khi bắt đầu trình bày. Một cách thay thế sẽ là đưa nó vào viewWillAppear nhưng sử dụng thuộc tính chuyển đổi Người điều phối mới trong iOS 8 để thêm mã khi quá trình chuyển đổi hoàn tất. Có thể tìm thấy thêm thông tin tại đây developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Acey

36

Trong mục tiêu c: Điều này đã giải quyết vấn đề của tôi khi trình bày bộ điều khiển chế độ xem trên đầu mpmovieplayer

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

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

    return topController;
}

34

Swift 3

Tôi đã có điều này tiếp tục đến với tư cách là một người mới và nhận thấy rằng các chế độ xem phương thức tải hiện tại có thể bị loại bỏ nhưng chuyển sang bộ điều khiển gốc là tốt nhất nếu bạn không cần hiển thị phương thức.

Tôi đã sử dụng cái này

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

Sử dụng điều này thay thế với tabController của tôi:

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

Chỉ cần điều chỉnh thành bộ điều khiển chế độ xem nếu bạn cần chuyển đổi giữa nhiều màn hình bảng phân cảnh.


16

Swift 3.

Gọi hàm này để lấy bộ điều khiển chế độ xem trên cùng, sau đó có bộ điều khiển chế độ xem đó.

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

Sử dụng:

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

1
Thanx @Jacob Davis cho điều này! Tôi đã sử dụng nó để trình bày một alertController nguyên nhân tôi đã nhận được cảnh báo: Cố gắng để có mặt ....
Gary Mansted

Điều này rất hữu ích. một số những gì đang nhận được bộ điều khiển trình bày Nhưng màn hình không xuất hiện. đột nhiên nó bị loại bỏ. Bất kỳ mã nào khác cần phải thực hiện? vui lòng đề xuất
Seethalakshmi_user8943692

13

cho SWIFT

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

1
Cảm ơn bạn! Đây là điều duy nhất giải quyết được lỗi này cho tôi. Tôi đang cố gắng trình bày một VC phương thức từ một chức năng được kích hoạt bởi trình nhận dạng cử chỉ, ngay sau khi chế độ xem được tải đầy đủ (trong Xcode 8 / iOS 10). Thật kỳ lạ, topControllerhàm này được trả về chính xác là VC giống như selftrong khi cố gắng trình bày trực tiếp bằng cách sử dụng self.presentViewController(myModalVC), nhưng không có lỗi phân cấp chế độ xem khi tôi chuyển VC trình bày bằng hàm của bạn.
Natalia

13

Bạn chỉ cần thực hiện một bộ chọn với độ trễ - (0 giây hoạt động).

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) 
}

Cảm ơn rất nhiều. Tôi đã bị mắc kẹt trong vấn đề này trong hơn một giờ.
Reza

Cảm ơn ... @objc func presentExampleController ()
William Choy,

Tôi nghĩ đó là một câu trả lời tuyệt vời!
mê cung

Đó là một bản hack (có thể hoạt động ngay bây giờ), nhưng sẽ thiết lập cho bạn một thứ gì đó bị hỏng trong những trường hợp không mong muốn.
William Grand

6

Swift 4

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

1
Một lời giải thích và ví dụ sẽ là hữu ích @AllenWixted
Eury Pérez Beltré

2

Đối với swift 3.0 trở lên

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

2

Tôi đã gặp lỗi này khi trình bày bộ điều khiển sau khi người dùng mở liên kết sâu. Tôi biết đây không phải là giải pháp tốt nhất, nhưng nếu bạn đang ở trong khung thời gian ngắn thì đây là một cách khắc phục nhanh chóng - chỉ cần bọc mã của bạn trong asyncAfter:

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

Nó sẽ cho thời gian để trình điều khiển trình bày của bạn gọi 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)

Điều này dường như hoạt động để đảm bảo nó là góc nhìn nhiều nhất.

Tôi đã gặp lỗi

Cảnh báo: Cố gắng trình bày myapp.testController: 0x7fdd01703990 trên myapp.testController: 0x7fdd01703690 có chế độ xem không nằm trong phân cấp cửa sổ!

Hy vọng điều này sẽ giúp những người khác với swift 3


1

Tôi đã thử rất nhiều cách tiếp cận! điều hữu ích duy nhất là:

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

1

Tất cả triển khai cho topViewController ở đây không hỗ trợ đầy đủ các trường hợp khi bạn có UINavigationControllerhoặc UITabBarController, đối với hai trường hợp đó , bạn cần xử lý khác một chút:

Đối với UITabBarControllerUINavigationControllerbạn cần một triển khai khác.

Đây là mã tôi đang sử dụng để tải 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

Swift Method và cung cấp một bản demo.

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

Sử dụng luồng chính để trình bày và loại bỏ bộ điều khiển chế độ xem đã làm việc cho tôi.

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

0

Thay vì tìm bộ điều khiển chế độ xem trên cùng, người ta có thể sử dụng

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

Trong đó viewController là bộ điều khiển mà bạn muốn trình bày Điều này rất hữu ích khi có nhiều loại chế độ xem khác nhau trong hệ thống phân cấp như TabBar, NavBar, mặc dù những chế độ khác có vẻ đúng nhưng hơi khó hiểu hơn

Bạn có thể tìm thấy kiểu trình bày khác trên apple doc


0

Các câu trả lời trước liên quan đến tình huống trong đó bộ điều khiển chế độ xem sẽ hiển thị chế độ xem 1) chưa được thêm vào hệ thống phân cấp chế độ xem hoặc 2) không phải là bộ điều khiển chế độ xem hàng đầu.
Một khả năng khác là một cảnh báo nên được đưa ra trong khi một cảnh báo khác đã được đưa ra và chưa bị loại bỏ.


0

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.