24/7 twenty-four seven

iOS/OS X application programing topics.

StoryBoardまたはXIBについて、ファイルごとにDeployment Targetを設定する

昨日はじめて知ったのですが、StoryBoardやXIBファイルはプロジェクトやターゲットのDeployment Targetとは別に、各ファイルごとに個別にDeployment Targetを設定することができます。

例えば、iOS 8以上にしか存在しないUIVisualEffectViewや、iOS 9以降でしか使えないUIStackViewをStoryBoardで配置して、プロジェクトのDeployment Targetを7.0(や8.0)にすると、下記のエラーでビルドに失敗します。

Main.storyboard: error: Class Unavailable: UIVisualEffectView prior to iOS 8.0

これを避けるためにはStoryBoardを使うことをあきらめ、コードでOSバージョンを分岐して、コードでUIコンポーネントを配置する必要があると思っていました。

しかし、StoryBoardにはファイルごとにDeployment Targetを設定できるので、新しいUIコンポーネントを配置しているStoryBoardについては、プロジェクトのDeployment Targetよりも高い値を指定します。

StoryBoardを選択して、File Inspectorの「Interface Builder Document」セクションの「Build For」がそれになります。

↑ たとえば、上記の例ではプロジェクトのDeployment Targetは7.0なのでiOS 8以上でしか使えないUIVisualEffectViewをStoryBoardで配置するとビルドエラーになりますが、そのStoryBoardのDeployment Targetを8.0以上にすることでビルドできるようになります。

もちろん、古いOSでStoryBoardを使ってしまうと実行時にクラッシュしてしまうので、OSのバージョンを判断して、ロードするStoryBoardを変更するようにします。

let storyboard: UIStoryboard

if #available(iOS 9, *, *) {
    storyboard = UIStoryboard(name: "Detail-iOS9", bundle: nil)
} else {
    storyboard = UIStoryboard(name: "Detail-iOS8", bundle: nil)
}

if let controller = storyboard.instantiateInitialViewController() {
    self.navigationController?.pushViewController(controller, animated: true)
}

↑ このようにすると、古いOS用のUIと新しいOS用のUIがStoryBoard単位で分けられますし、レイアウトはStoryBoardが使えるので、スッキリした構成になります。

iOS 9ではUIStackViewを使い、古いOSではUICollectionViewを使うように切り替えるなども簡単にできます。

【参考】

stackoverflow.com