Search code examples
iosobjective-cuikit

Using safeAreaInsets get the top edge of my UIWindow's safe area works in iOS 13, but not iOS 11?


I have a method in my portrait-orientation iOS app that attempts to return the value in points of the top edge of the main window's safe area, using safeAreaInsets:

+ (double)screenTopEdge
{
    UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
    if (@available(iOS 11, *)) {
        return mainWindow.safeAreaInsets.top;
    } else {
        // (Handle older iOS verisons)
    }
}

When I run this under iOS 13, it works as expected: It returns 44.0 when run on an iPhone X, and 20.0 when run on an iPhone 8 or an iPad Mini.

However, when I run this under iOS 11, it returns 0.0, on all of the aforementioned devices (even though the status bar is shown/visible -- not hidden).

I get this behavior even if I call this method from late in the rendering pipeline for the current view controller, including from the viewDidLayoutSubviews or viewDidAppear methods.

I've been able to reproduce this on a freshly-created iOS Storyboard-based project in XCode 11.1, so I don't think this behavior is due to any odd configuration in my project.

I've been able to work around this by checking the height of the status bar instead:

return [UIApplication sharedApplication].statusBarFrame.size.height;

However, why doesn't the code that uses safeAreaInsets.top work as expected under iOS 11? What's the right way to get the top safe area inset of the main application window in iOS 11+?


Solution

  • This is an old question, about a very outdated OS, but, for reference, the answer is that safe area insets were buggy on iOS 11. In some cases, as seen here, the window did not have correct safe area insets, but views lower in the window's view hierarchy did. In other cases, values were correct for notched devices (iPhone X) but not for others (e.g. iPhone 8 Plus). Most of these issues were ironed out in iOS 12 and completely fixed in iOS 13.