18

This might be a simple question but since I'm a beginner, it is best to ask.

As the title says what should I use instead of UIScreen.mainScreen().applicationFrame since it's deprecated in 9.0.

If possible it would be great if you can provide me with a sample or example ,since I find Apples document difficult.

Currently I use the code below but I wish to change it to the new version. I would love to hear from you!

  let sizeRect = UIScreen.mainScreen().applicationFrame
  let posX = arc4random_uniform(UInt32(sizeRect.size.width))
  let posY = arc4random_uniform(UInt32(sizeRect.size.height))
  Enemy.position = CGPoint(x: CGFloat(posX), y: CGFloat(posY))
Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
Jennifer
  • 1,822
  • 2
  • 20
  • 45

6 Answers6

20

Use

let rect1 = UIScreen.mainScreen().bounds // Returns CGRect
let rect2 = UIScreen.mainScreen().bounds.size // Returns CGSize

Swift 3+ :

let rect1 = UIScreen.main.bounds // Returns CGRect
let rect2 = UIScreen.main.bounds.size // Returns CGSize
VRAwesome
  • 4,721
  • 5
  • 27
  • 52
15

I know that UIScreen.mainScreen().bounds is the recommended alternative; however, it's not the exact equivalent to UIScreen.mainScreen().applicationFrame, particularly when your application does NOT occupy the whole screen, which happens with Split View and Slide Over feature on certain iPads.

In that case, this is a good alternative: UIApplication.sharedApplication.keyWindow.frame. (of course keyWindow has to be available, that is, you did invoke makeKeyAndVisible)

Stephenye
  • 806
  • 6
  • 12
  • 1
    This is THE answer. UIScreen.main.bounds does **not** work in certain situations (i.e. when you're on a phone call). – ChrisRockGM Nov 30 '17 at 16:25
  • I agree this is the answer. For instance, if your app is running side to side to another app, you can do `self.window.frame = UIApplication.shared.keyWindow.bounds` or `self.window.frame = [UIApplication sharedApplication].keyWindow.bounds;` for Obj-C and most of the times people call makeKeyAndVisible after that but in this case you have to do it first like Stepheneye said otherwise you will get a nil value from keyWindow. – Jesus Rodriguez Jan 28 '20 at 09:11
2

As of swift 3 you need to use it like this now.

let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height
Sam B
  • 27,273
  • 15
  • 84
  • 121
1

For:

let width = UIScreen.mainScreen().bounds.width

and for:

let height = UIScreen.mainScreen().bounds.height
Orkhan Alizade
  • 7,379
  • 14
  • 40
  • 79
1

Unfortunately UIScreen.main and UIScreen.mainScreen() have both been deprecated since iOS 16.

Apple discourages the use of this symbol. Use a UIScreen instance found through context instead. For example, reference the screen that displays a view through the screen property on the window scene managing the window containing the view.

As usual the Apple document is great at telling you what not to do, but seldom give you examples of what to do. So after some searching and testing I came up with my own solution.

I created a helper class with static functions giving me access to the current scene and from there the window and screen.

This solution only works for single window apps such as iOS and will need some additional work for iPad and macOS apps.

My solution was derived from a combination of the responses in this thread. Both answers create a UIWindow? variable in the main app entry.

The First Response

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

    [...]
}

The Second Response

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

I'm not in favor of the second response because it creates a new UIWindow from the UIWindowScene. You have access to an array of windows from the UIWindowScene.

My first attempt at this solution is to create a helper and convenience functions, and then exposing those onto View with convenience functions.

Helper

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

I chose to access to UIScene from the delegate instead of casting UIScene to UIWindowScene because according to Apple's documentation for UIScene it is:

An object that represents one instance of your app's user interface.

Reading Apple's documentation for UIWindowScene convinced me that getting it through a delegate is the more reliable way. I am curious if using a UISceneConfiguration entry in the info.plist is better?

Extension

extension View {
    var scene: UIScene? {
        return Application.scene
    }
    
    var window: UIWindow? {
        return Application.window
    }
    
    var screen: UIScreen? {
        return Application.screen
    }
}

I'm not a seasoned Swift developer so I am confident there is a better solution. I wonder what a better solution might be? It seems that UIScreen.main is an exceptionally common object it would be great to establish a new pattern for it's use.

David Geere
  • 404
  • 5
  • 10
0

Swift 3+:

let width = UIScreen.main.bounds.width
let height = UIScreen.main.bounds.height
Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71