[Swift] マルチプラットフォームで使えるコードを記述する方法

Swift

     

TAGS:

⌛️ < 1 min.
Xcode 12 になってから、マルチプラットフォーム対応が多くみられるようになりましたが、マルチプラットフォーム対応のコードをを記述する方法を説明します

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.1
  • Xcode 12.3

@available と #if の使い分け

対象とするプラットフォームで 定義されている場合は、@available 等で、利用可能となったバージョン等を指定することで、細かな使い分けが可能となります。

しかし、UIFont のような 特定のプラットフォームのみで定義されている場合は、#if 等で、コンパイル対象から外すことをしないと、未サポートプラットフォーム向けにはコンパイルすらできません。

Swift には、(そのためだけではありませんが)マルチプラットフォーム対応するのに便利な機能が実装されていますので、以下のような機能を使って記述していくことになります。

#if os(XX)
XX という OS 環境でのみ使えるコードを囲う
@available(…)
特定の os や バージョン で導入/廃止 されたコードに対して付与する

#if の例

macOS 向けの特殊処理


#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


typealias MyString = String
let text:MyString

上記は、text を MyString 型と定義していますが、実際には、String 型として定義されます。このように、実際の型に別名を割り当てることができるようになります。

typealias を使った例

先の #if と組み合わせることで、コード部分を綺麗に共有化することができます。

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
  }
}
コード解説
  1. typealias を使って、Color の差異を隠します
  2. typealias で定義した型で、定義します
  3. (どちらにも存在するメソッドであれば)具体的な型を明示せずに使用することができます

# 一方にしかない機能を使用すると、機能が無い方のプラットフォーム上でコンパイルできない・期待通りに動作しない等になりますので注意が必要です。

まとめ:1つのコードを マルチプラットフォームで使えるようにする方法

1つのコードを マルチプラットフォームで使えるようにする方法
  • 共有化できない箇所は、#if で分ける
  • ロジックは、typealias を使って、共有化する

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です