2

我试图按照本教程创建一个多屏应用程序:

https://www.youtube.com/watch?v=UYviLiI2rlY&t=774s

不幸的是,在 25:00 - 26:00 分钟,我收到一个错误,并且我的外部屏幕保持黑色:

[Assert] Error in UIKit client: -[UIWindow setScreen:] should not be called if the client adopts
UIScene lifecycle. Call -[UIWindow setWindowScene:] instead.

我的代码是:

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var textView: UITextView!
    var additionalWindows = [UIWindow]()

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification, object: nil, queue: nil) { [weak self] notification in
            guard let self = self else {return}

            guard let newScreen = notification.object as? UIScreen else {return}
            let screenDimensions = newScreen.bounds

            let newWindow = UIWindow(frame: screenDimensions)
            newWindow.screen = newScreen

            guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "PreviewViewController") as? PreviewViewController else {
                fatalError("Unable to find PreviewViewController")
            }

            newWindow.rootViewController = vc
            newWindow.isHidden = false
            self.additionalWindows.append(newWindow)
        }
    }


}

newWindow.screen = newScreen而且我在:中有一个弃用警报,Setter for 'screen' was deprecated in iOS 13.0但我找不到任何有用的东西,而且对于如何解决这个问题也没有过于复杂。

4

2 回答 2

3

请注意,您“应该”根据externalWindow.rootViewController实例化 VC

在我的例子中,我使用外部显示器来呈现 a custom UIView(),所以我使用一个空的UIViewController(),然后将我的视图添加到它。

private func setupExternalScreen(screen: UIScreen, retryUntilSet: Bool = true, retryTimesUntilDiscarded: Int = 0) {
    var matchingWindowScene: UIWindowScene? = nil
    let scenes = UIApplication.shared.connectedScenes
    for item in scenes {
        if let windowScene = item as? UIWindowScene {
            if (windowScene.screen == screen) {
                matchingWindowScene = windowScene
                break
            }
            }
    }
    if matchingWindowScene == nil {
        if true == retryUntilSet {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                if retryTimesUntilDiscarded < 5 {
                        self.setupExternalScreen(screen:screen, retryUntilSet: false, retryTimesUntilDiscarded += 1)
                } else {
                    let alert = UIAlertController(title: "Not connected", message: "Reconnect the display and try again", preferredStyle: .alert)
                        let ok = UIAlertAction(title: "Ok", style: .default, handler: nil)
                        alert.addAction(ok)
                        self.present(alert, animated: true, completion: nil)
                }
            }
        }
        return
    }
    externalWindow = UIWindow(frame: screen.bounds)
    externalWindow.rootViewController = UIViewController()
    airplayView.frame = externalWindow.frame
    if !externalWindow.subviews.contains(airplayView) {
        externalWindow.rootViewController?.view.addSubview(airplayView)
        if let _ = view.window {
            view.window?.makeKey()
        }
    } else {
        airplayView.updateValues()
    }

    externalWindow.windowScene = matchingWindowScene
    externalWindowWindow.isHidden = false
}

如果您的应用需要 iOS<13,您可能需要使用if #available(iOS 13.0, *) {} 来决定如何设置您的外部屏幕。

忘了提...externalWindow在我要求使用第二个屏幕的 ViewController 中声明

lazy var externalWindow = UIWindow()
于 2020-05-20T15:24:03.917 回答
3

连同此处提供的答案,我能够使其在模拟器中工作。对于 iOS 13+,您似乎必须在UIApplication.shared.connectedScenes.

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var textView: UITextView!
    var additionalWindows = [UIWindow]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification, object: nil, queue: nil) { [weak self] notification in
            guard let self = self else {return}
            
            guard let newScreen = notification.object as? UIScreen else {return}
            // Give the system time to update the connected scenes
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                // Find matching UIWindowScene
                let matchingWindowScene = UIApplication.shared.connectedScenes.first {
                    guard let windowScene = $0 as? UIWindowScene else { return false }
                    return windowScene.screen == newScreen
                } as? UIWindowScene
                
                guard let connectedWindowScene = matchingWindowScene else {
                    fatalError("Connected scene was not found") // You might want to retry here after some time
                }
                let screenDimensions = newScreen.bounds
                
                let newWindow = UIWindow(frame: screenDimensions)
                newWindow.windowScene = connectedWindowScene
                
                guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "PreviewViewController") as? PreviewViewController else {
                    fatalError("Unable to find PreviewViewController")
                }
                
                newWindow.rootViewController = vc
                newWindow.isHidden = false
                self.additionalWindows.append(newWindow)
            }
        }
    }
}

我不确定时间,.now() + 1似乎可以在模拟器上工作,但我还没有尝试过真正的硬件,所以你可能想调整一下。

于 2021-06-29T15:54:06.887 回答