たまーに、使う。そのたまーに使うから思い出せない。
ので、メモ書きです。
バージョンでの処理について
プラットフォームやバージョンごとに利用可能・不可能なコードの断片を書くことは、変化し続けるアプリ開発の状況で必要だと考えます。
個人的な意見、バージョンごとにコードの断片を書くことは Issue に書くより、コードに書く方が良いと考えています。
理由として、Issue に書いてしまうと他の Issue に埋もれて隠れてしまい、忘れ去られてしまうからです。TODOリストなどでも、いつまで経っても処理されないタスクってありますよね。
この問題を解決するためにも、新しいAPIを使って実装し、バージョンごとに分割する手法を取ると良いかなぁと考えます。
この記事では、バージョンごとに処理を分ける方法について解説します。
OSのバージョンで処理を分ける
iOS開発において、よく目にする処理だと思います。#available
を使うとOSのバージョンごとにコードを分けることができます。
if #available(iOS 15.0, *) {
/// iOS 15.0以降の時はここを通る
} else {
/// iOS 15.0より前の時はここを通る
}
guard #available(iOS 15.0, *) else {
/// iOS 15.0より前の時はここを通る
}
/// iOS 15.0以降の時はここを通る
@available
と #available
の違い
Swift API には、available
と調べると、@ があるものと、# があるものの、2通りがあります。それぞれ何が違うのでしょうか。
公式ドキュメントでは以下のように説明されています。
-
@available
: 特定のターゲットプラットフォームのアプリを構築する際に宣言を使用するかどうかを制御する -
#available
: 必要なプラットフォームとバージョン状況に基づいて条件付きでコードを実行します
@available
@available
を使うことで、利用可能なクラスまたはメソッドを制御することができます。
例えば、iOS14よりも低いバージョンでサポートするプロジェクト内に以下のクラスのインスタンスを作成するとエラーが発生します。
@available(iOS 14, *)
final class NewAppIntroduction {
// 任意のインスタンス
}
このコードは、#available
を使って以下のように実装すると使えるようになります。
if #available(iOS 14, *) {
let appIntroduction = NewAppIntroduction()
} else {
// iOS14 より前の処理
}
また、@available
を使って同様な処理を作成しても作ることができます。
@available(iOS 14, *)
func launchNewAppIntroduction() {
let appIntroduction = NewAppIntroduction()
}
非推奨または廃止をマークする
@available
は非推奨・廃止としてマークすることもできます。
以下のコードは、iOS12より高いバージョンでは非推奨とし、iOS13より高いバージョンでは廃止としてアラートが表示されます。
@available(iOS, deprecated: 12, obsoleted: 13, message: "We no longer show an app introduction on iOS 14 and up")
func launchAppIntroduction() {
// ..
}
メソッド名の変更をマークする
OSSやSDK、Packageを作成している人は、実装者へ向けてコードを新しいAPIを使用させたい場合に以下のように実装すると良いでしょう。
@available(*, unavailable, renamed: "launchOnboarding")
func launchAppIntroduction() {
// 古い処理
}
func launchOnboarding() {
// 新しい処理
}
廃止としてマークしていることに注意してください。renamed では、代わりにどのAPIを使えば良いかを示します。
プラットフォームで処理を分ける
iOS と MacOS で処理を分けたい場合は、以下のように行います。
#if os(iOS)
// iOS に関する処理
# else
// その他プラットフォームに関する処理
# endif
また、SimulatorやMac Catalystなど、特定の環境向けにコンパイルしたり、コンパイルしないようにしたりすることもできます。
#if targetEnvironment(simulator)
// シュミレーターに関する処理
#endif
参考文献