もちろんできません
safeAreaLayoutGuideはiOS 11+のみで使えるので、iOS 10等をサポートしているとエラーになります。
大抵の場合は、画面端からの代わりにsafeAreaを使って、iPhone Xでもレイアウト崩れないようにしたいと思います。
とはいえ、レイアウトごとに
if #available(iOS 11.0, *) {
view.safeAreaLayoutGuide.leftAnchor
} else {
view.leftAnchor
}
みたいにするのは冗長です。
これを同じように扱えればよいわけです。
第一案
結果
UIViewのAnchorを、UILayoutGuideとして取り出すことで対応しました。
let safeAreaLayoutGuide = view.safeLayoutGuideOrSelfLayoutGuide()
これでiOS 11以上ならsafeAreaLayoutGuideが、iOS 10以下では自分自身のLayoutGuideが返されます。
実装
まず、leftAnchorなどはUIViewのプロパティなので、ProxyするクラスをUILayoutGuideを継承して作ります
private final class UIViewLayoutGuideProxy: UILayoutGuide {
private unowned var _base: UIView
override var leftAnchor: NSLayoutXAxisAnchor {
return _base.leftAnchor
}
}
そして、このiOS 10以下ではこのProxyを返すようなメソッドを生やせば完了です。
extension UIView {
func safeLayoutGuideOrSelfLayoutGuide() -> UILayoutGuide {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide
} else {
return UIViewLayoutGuideProxy(self)
}
}
}
Gist
以下でソースを公開しています(案1の方)
第二案
extension UIView {
var safeLeftAnchor: NSLayoutXAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide
} else {
return self.leftAnchor
}
}
}
みたいなのも考えましたが、せっかく .leftAnchor
の名前はUIViewでもUILayoutGuideでも揃っているので、崩したくないなと思いました。
が、以下のようにviewがdeinitされた後に呼ばれる可能性がなくなるので、こっちのほうがいいかもしれません、、、(今更)
let tmp = view.safeLayoutGuideOrSelfLayoutGuide()
// viewがdeinitされた後に呼ぶと_baseがnilで落ちる
print(tmp.leftAnchor)
案2として同じGistの下側にあります!
第三案
Rxみたいにしてみた。これが一番いいかも
view.safeAreaLayoutGuideCompatible.leftAnchor
という感じ