Sponsor Link
環境&対象
- macOS Big Sur 11.1
- Xcode 12.3
@available と #if の使い分け
対象とするプラットフォームで 定義されている場合は、@available 等で、利用可能となったバージョン等を指定することで、細かな使い分けが可能となります。
しかし、UIFont のような 特定のプラットフォームのみで定義されている場合は、#if 等で、コンパイル対象から外すことをしないと、未サポートプラットフォーム向けにはコンパイルすらできません。
Swift には、(そのためだけではありませんが)マルチプラットフォーム対応するのに便利な機能が実装されていますので、以下のような機能を使って記述していくことになります。
- #if os(XX)
- XX という OS 環境でのみ使えるコードを囲う
- @available(…)
- 特定の os や バージョン で導入/廃止 されたコードに対して付与する
#if の例
#if os(macOS)
/* macOS 向け処理 */
#endif
上記のコードは、macOS をターゲットとして指定した時だけ、コンパイル対象となります。
それぞれの OS での特殊処理が必要な場合には、上記の方法を使います。
typealias との組み合わせ
macOS だけでの処理や iOS だけでの処理は、上記の方法で記述できますが、それだけでは解決しないケースがあります。
プラットフォームから提供される機能が同一(or 似ている)けれど、クラス名が異なるケースです。
例えば、NSFont(@macOS), UIFont(@iOS) 等を使いたい時です。
Mac Catalyst が導入されて、macOS 上でも UIFont 等が使えるようになりましたが、まだ UI_XX と NS_XX の差異で困るケースはあります。
そこでうまく使いたいのが、typealias です。
typealias MyString = String
let text:MyString
上記は、text を MyString 型と定義していますが、実際には、String 型として定義されます。このように、実際の型に別名を割り当てることができるようになります。
typealias を使った例
先の #if と組み合わせることで、コード部分を綺麗に共有化することができます。
// (1)
#if os(macOS)
typealias SysColor = NSColor
#elseif os(iOS)
typealias SysColor = UIColor
#endif
struct MyEntity {
// (2)
let color:SysColor
// (3)
func cgColor() -> cgColor{
return color.cgColor
}
}
- typealias を使って、Color の差異を隠します
- typealias で定義した型で、定義します
- (どちらにも存在するメソッドであれば)具体的な型を明示せずに使用することができます
# 一方にしかない機能を使用すると、機能が無い方のプラットフォーム上でコンパイルできない・期待通りに動作しない等になりますので注意が必要です。
まとめ:1つのコードを マルチプラットフォームで使えるようにする方法
- 共有化できない箇所は、#if で分ける
- ロジックは、typealias を使って、共有化する
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link