[iOS] Property Wrapper の概要について

はじめに

SwiftUI でもよく使われているProperty Wrapper についてさらっとまとめます!

Property Wrapper とは

ある「プロパティ」を「何らかの処理を施したラップ後のプロパティ」に変更する仕組みです。

@HogePropertyWrapper var a = 1

と書いた場合、a というプロパティは
HogePropertyWrapper にて何らかの処理を施された後(= 何らかの処理をラップした後)のプロパティ、
というものに変質します。

プロパティを get / set するときの何らかの処理をメソッド化して分離し、
それを適応したプロパティに対し共通処理として使いまわせる、
というのが Property Wrapper の思想になります。

Property Wrapper の書き方

とっかかりとして、 2速で歩くヒト:【Swift 5.1】Property Wrappersとは?
というブログ記事がとても参考になると思います。

struct, enum, class で定義可能で、wrappedValue というプロパティを定義する必要があります。

以下、Swift.org のコード そのままですが例示します。

@propertyWrapper
struct TwelveOrLess {
    private var number: Int
    init() { self.number = 0 }
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

これは Int の上限を12に制限する Property Wrapper となります。

プロパティにこの TwelveOrLess の処理を適応するには、以下のように @ をつけて宣言します。

class HogeClass {
    @TwelveOrLess var number: Int
    func hogeMethod() {
        number = 100
        print("🐱 mumber: \(number)") // "🐱 mumber: 12" と表示される
    }

Property Wrapper の仕組み

この @TwelveOrLess var number: Int の部分は、コンパイル時に以下のように展開されます。

private var _number = TwelveOrLess()
var number: Int {
    get { return _number.wrappedValue }
    set { _number.wrappedValue = newValue }
}

_number というプロパティができ、 number プロパティへのアクセスは
実態として _number.wrappedValue へアクセスする、という処理に変更されます。

number_number 、つまり TwelveOrLess のインスタンスをラップした値、ということですね。

これが PropertyWrapper の仕組みです!

Property Wrapper の初期化

Property Wrapper を適用したプロパティの初期化は以下のように書きます。

@TwelveOrLess var number: Int = 1

これは number プロパティに初期値1を設定しようとしています。

Swift はこれを以下のコードに変換します。

@TwelveOrLess(wrappedValue: 1) var number: Int

TwelveOrLess 側には以下のコードが必要になります。

@propertyWrapper
struct TwelveOrLess {
    // 略
    init(wrappedValue: Int) { self.number = wrappedValue } // メソッドの中身はお好きに
    // 略
}

このwrappedValue の初期化メソッドを書かないと
Argument passed to call that takes no arguments というエラーが出るかと思います。

複数の引数で初期化する場合

以下のように書きます。

@TwelveOrLess(wrappedValue: 1, hoge: "hoge") var number: Int
@propertyWrapper
struct TwelveOrLess {
    // 略
    private var hoge: String
    init(wrappedValue: Int, hoge: String) {
        self.number = wrappedValue
        self.hoge = hoge
    }
    // 略
}

Property Wrapper の概要については以上となります。

Projected Value という概念もありますが、それはまた別の機会に…。

最後に

以上です。
お疲れ様でした!

[iOS] Property Wrapper の概要について」への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。