この投稿は...
SwiftUIフレームワークでアプリを開発するにあたって、必須のAPIであるプロパティラッパーが「どのような仕組みで動作しているのか」を、シンプルな例を挙げて解説します。
Swiftを基礎から学ぶには
自著、工学社より発売中の「まるごと分かるSwiftプログラミング」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。
また、Swiftプログラミングを基礎から動画で学びたい方には、Udemyコース「今日からはじめるプログラミング」をお勧めします。
実行環境
Swift 5.9
Xcode 15
macOS Sonoma 14.3.1
プロパティラッパーが解決できること
以下に定義するのは、「短い直線」をモデル化するShortLine
型です。
struct ShortlLine {
private var _length = 0 // 外部からは見えない「隠しプロパティ」
var length: Int {
get { return _length }
set { _length = min(newValue, 10) }
}
}
インスタンスの長さを保持するのは「隠しプロパティ」ですが、プログラマーは計算プロパティを介して「長さの値」にアクセスします。
といっても、プログラマーは隠しプロパティが存在することも、アクセスしているのが計算プロパティであることも意識する必要はありません。
実際、インスタンスの長さに「10
より大きい数」を設定すると、自動的に値が調整されて10
になります。
var line = ShortlLine()
line.length = 9
line.length // 9
line.length = 15
line.length // 10
今度は、似たようなオブジェクトとして「軽い重量」をモデル化する場合を考えます。
例えば、軽い重量をモデル化する構造体は、以下のように定義できます。
struct RightWeight {
private var _weight = 0
var weight: Int {
get { return _weight }
set { _weight = min(newValue, 10) }
}
}
やはり、インスタンスの重さに「10
より大きい数」を設定すると、10
に調整してくれます。
var mass = rightWeight()
mass.weight = 12
mass.weight // 10
「短い直線」も「軽い重量」も、本質的には「数値を10以下に調整する」ことをモデル化しています。
これは、以下のような構造体として定義できます。
struct TenOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 10) }
}
}
「短い直線」と「軽い重量」の定義はTenOrLess
型を利用することによって、以下のように実装を簡略化できます。
// 短い直線
struct ShortlLine {
private var _length = TenOrLess()
var length: Int {
get { return _length.wrappedValue }
set { _length.wrappedValue = newValue }
}
}
// 軽い重量
struct RightWeight {
private var _weight = TenOrLess()
var weight: Int {
get { return _weight.wappedValue }
set { _weight.wappedValue = newValue }
}
}
TenOrLess
型を定義したことによって、「値を10
以下に調整する」ためのコードを再利用できました。
プロパティラッパーの利点
上の例で示したコードは、プロパティラッパーを使用すると限りなくシンプルに記述できます。
プロパティラッパーを利用するには、プロパティの本質をモデル化する型に@propertyWrapper
属性をマークします。
こうすることで、TenOrLess
プロパティラッパーを利用できるようになります。
@propertyWrapper
struct TenOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 10) }
}
}
TenOrLess
プロパティラッパーを利用すると、「短い直線」と「軽い重量」は以下のように定義できます。
// 短い直線
struct ShortlLine {
@TenOrLess var length: Int
}
// 軽い重量
struct RightWeight {
@TenOrLess var weight: Int
}
プロパティに@TenOrLess
キーワードをマークするだけで、以前と同じ機能を実装できます。
var newLine = ShortlLine()
newLine.length = 12
newLine.length // 10
このように、プロパティラッパーは実装を抽象化して、難しいことを意識せずに機能を利用できるようにします。
SwiftUIフレームワークでは@State
や@Binding
、@Bindable
などのプロパティラッパーを利用せずに実際的なアプリケーションを開発することはできません。
といっても、プロパティラッパーの利点は「実装を意識することなく、恩恵を受けられる」ことです。
それらのプロパティラッパーがどのように実装されて、背後でどのように機能しているかを理解する必要はありません。