prefersStatusBarHidden が false を返すように実装しても iPhone の Landscape モードではステータスバーが常に非表示となる

# 概要

最近のバージョンの iOS を搭載した iPhone の Landscape モードでステータスバーを表示させる方法がないか、いろいろと試してみたのですが、どうやらそのような方法はないようです。（方法が見つかりませんでした。）

# 確認環境

## ビルド環境
* macOS 10.15.5
* Xcode 11.5 (11E608c)
* Deployment Target: iOS 11.0
* User Interface が Storyboard の Xcode プロジェクトを使用

## 実行環境
* iPhone 11 Pro Max (iOS 13.5.1)
* iOS Simulator (iPhone Xs Max, iOS 12.4)
* iOS Simulator (iPad Air 2, iOS 12.4)

# 試したこと

## `prefersStatusBarHidden` が `false` を返すようにする

ステータスバーを表示させたい画面の View Controller で `UIViewController` クラスのプロパティ `prefersStatusBarHidden`[^1] をオーバーライドして `false` を返すようにします。つまり、常にステータスバーを表示するように設定するのです。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override var prefersStatusBarHidden: Bool {
        return false
    }
}
```

## `Info.plist` で `View controller-based status bar appearance` の値に `YES` を設定

`prefersStatusBarHidden` をオーバーライドしただけでは、対象の画面を表示した時や画面回転時に `prefersStatusBarHidden` の値が参照されません。

次の画像のように、 Xcode で対象のビルドターゲットについての `Info.plist` の内容を表示し、その中で `View controller-based status bar appearance` の項目の値に `YES` を設定します。これにより、上述の `prefersStatusBarHidden` の値が使用されるようになります。

![スクリーンショット 2020-06-23 23.52.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200832/cf02f26a-d926-18ec-3d45-683e89b2e0ae.png)

なお、`View controller-based status bar appearance` という項目は、 `Info.plist` のソースコードでは `UIViewControllerBasedStatusBarAppearance`[^2] というキーで表されます。

```xml:Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<!-- 省略 -->
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<true/>
</dict>
</plist>

```

## なるべくシンプルな画面構成で動作確認

`UINavigationController` や `UITabBarController` などの Container View Controller を使う場合、 `childForStatusBarHidden` を適切に設定しなければなりません。今回は `prefersStatusBarHidden` の値の使い方を中心に確認したいため、 こうした Container View Controller は使用せずに、なるべくシンプルな画面構成で動作確認することにしました。

Xcodeの新規プロジェクト作成メニューから `Single View App` テンプレートを選択して Xcode プロジェクトを作成し、そのプロジェクト内の `ViewController` クラスに変更を加えることにより動作確認しました。

# 確認結果

上記の設定を試してみたのですが、 iPhone では画面表示時や画面回転時に `prefersStatusBarHidden`が呼び出されるものの、 Landscape モードのときにはステータスバーが表示されません。（ iPad では常に、また、iPhone が Portrait モードのときには、ステータスバーが表示されます。）

# Developer Documentation の記述から判断できること

あらためて `prefersStatusBarHidden` についての Developer Documentation[^1] の Discussion を確認してみたところ、次のように書かれていました。

```
By default, this method returns false with one exception. For apps linked against iOS 8 or later, this method returns true if the view controller is in a vertically compact environment.
```

この記述によると、 `prefersStatusBarHidden` が返す値には以下の規則性があるということです。

* デフォルトでは `false` を返す。
* iOS 8 以降にリンクされたアプリでは View Controller の Size Class の横幅が `Compact` の場合には `true` を返す。

また、 [Human Interface Guidelines に記載されている各デバイスの Size Class の一覧表](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/)を見ると、 iPhone の全機種の Size Class の横幅が `Compact` であることがわかります。 

実際に動作確認してみた結果と照らし合わせてみると、オーバーライドした `prefersStatusBarHidden` が常に `false` を返すようになっていたとしても、その View Controller のSize Class の横幅が `Compact` の場合には、 `true` を返しているものとして iOS の内部では評価されているようです。

[^1]: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden
[^2]: https://developer.apple.com/documentation/bundleresources/information_property_list/uiviewcontrollerbasedstatusbarappearance