很不幸的是UIScreen.main
和UIScreen.mainScreen()
自iOS 16以来已经被废弃了。
Apple不鼓励使用此符号。请改用通过上下文找到的UIScreen实例。例如,通过窗口场景管理包含视图的窗口上的screen属性引用显示视图的屏幕。
通常情况下,苹果文档告诉你不要做什么,但很少给出示例告诉你该怎么做。所以在一番搜索和测试之后,我想出了自己的解决方案。
我创建了一个帮助类,其中包含静态函数,可以让我访问当前场景,从而访问窗口和屏幕。
此解决方案仅适用于单窗口应用程序,例如iOS,并且对于iPad和macOS应用程序需要进行额外的工作。
我的解决方案源于this thread中响应的组合。两个答案都在主应用程序入口中创建了一个UIWindow?
变量。
第一次响应
@main
struct DemoApp: App {
var window: UIWindow? {
guard let scene = UIApplication.shared.connectedScenes.first,
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
let window = windowSceneDelegate.window else {
return nil
}
return window
}
[...]
}
第二个 响应
@main
struct TestApp: App {
var window: UIWindow? {
guard let scene = UIApplication.shared.connectedScenes.first,
let windowScene = scene as? UIWindowScene else {
return nil
}
return .init(windowScene: windowScene)
}
}
我不赞成第二种响应,因为它会从UIWindowScene
创建一个新的UIWindow
。你可以从UIWindowScene
访问窗口数组。
我对这个问题的第一次尝试是创建一个帮助器和方便函数,然后使用方便函数将其暴露到View
上。
帮助器
struct Application {
public static var scene: UIScene? {
guard let scene = UIApplication.shared.connectedScenes.first else {
return nil
}
return scene
}
public static var window: UIWindow? {
guard let scene = self.scene,
let delegate = scene.delegate as? UIWindowSceneDelegate,
let window = delegate.window else {
return nil
}
return window
}
public static var screen: UIScreen? {
guard let window = self.window else {
return nil
}
return window.screen
}
}
我选择从代理访问UIScene
,而不是将UIScene
强制转换为UIWindowScene
,因为根据苹果文档中对UIScene
的描述:
表示应用程序用户界面的一个实例的对象。
阅读苹果文档中关于UIWindowScene
的说明使我相信通过代理获取它是更可靠的方法。我好奇是否在info.plist中使用UISceneConfiguration
条目会更好?
扩展
extension View {
var scene: UIScene? {
return Application.scene
}
var window: UIWindow? {
return Application.window
}
var screen: UIScreen? {
return Application.screen
}
}
我不是一名经验丰富的Swift开发者,因此我相信肯定有更好的解决方案。我想知道有什么更好的解决方案吗?看起来UIScreen.main
是一个异常常见的对象,建立一个新模式来使用它将会很棒。