0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Swift 13 Property Wrapper 財産の上紙せせ

Posted at

此れは、Swift5.1から出てきて Class{}Struct{}の実装部に{var{get{}}}{var{set{}}}そしてcomputed property コードの重複を減らす方法を提供します。
Screenshot 2023-10-21 at 9.55.05 PM.png

十三・壱 Property Wrapper

壱・甲 Property Wrapperについて

ClassStruct {Instance{}}にある{Property = }で値を割り当うとか、
接近する時値を保存するとか、読み込む前に変更作業とValidationをする時が度々あります。実はcomputed propertyとしてする事ができます。
だが、様々な ClassStructで生成されたComputed Propertyは似た様なパータンを持っている場合にが頻繁にあります。
Swift5.1前には、computedPropertyを共有する唯一な方法はいちいちClassStructで含まるだけでした。
その短所を補完するためにPropertyWrapperを導入しました。
此れは基本的にcomputedPropertyの機能を個別ClassStructと分離できるようにして、アフリコードで再利用できる様にします。

壱・乙 Property Wrapper例題

都市の名前を保存するString Propertyを持っているStruct{}あるとしよう。

struct Address{
    var city: String
}

使用者が都市の名前をどうやって入力するかはかかわらずに大文字に保存されると、次の様にComputedPropertyをStruct{}で追加できます。

struct Address{
    private var cityname: String = ""
    
    var city: String {
        get {cityname}
        set {cityname = newValue.uppercased()}
    }
}

都市の名前が{Property = }で割り当てられると、演算プロパティのsetがprivate cityname var で値を保存する前に大文字に変更する事になる
今作ったStruct{}をテストする為に次の様にします。

var address = Address()

address.city = "London"
print(address.city)
>> LONDON

演算フロパティは都市名前の文字を大文字に変更されました。
もし、この様な作業が他の StructとかClassでひつよなら、今のコードをコピーして必要なところで貼り付ける方法もあります。
だが、今の例題はコードの多さが少ないからそうなるですけど、大量のコードと複雑な演算がある場合には適度はないと思います。
演算フロパティを使用する代わりに、このロジックをフロパティラッパーで実装できます。
例えば、次の宣言部は文字列を大文字で変更すると設計されたFixCaseというフロパティラッパーを実装できます。

@propertyWrapper
struct FixCase {
    private(set) var value: String = ""
    
    var wrappedVlaue: String {
        get { value }
        set { value = newValue.uppercased()}
    }
    init(wrappedValue initialValue: String){
        self.wrappedValue = initialValue
    }
}

フロパティラッパーは propertyWrapper 指示者を使って宣言され、 Class{}Struct{}中で実装されます
全てのPropertyWrapperは値を変更するとかValidationTestする{var{get{}}}{var{set{}}}コードが含まれるwrappedValue Propertyを持つべきである。
{init{}}は選択事項で含めることができる。前のコードには{init{}}が大文字で変更すしてprivate var で保存するwrappedValue {Property = }で割り当てます。
PropertyWrapperを使う為にはこのこの動作が必要な Class{}とかStruct{}{Property = }前で@FixCase支持者を付けてばいいです。

struct Contact{
    @FixCase var name:String
    @FixCase var city:String
    @FixCase var country:String
}

var contact = Contact(name: "John Smith", city:"London", country: "United Kingdom")
print("\(contact.name),\(contact.city),\(contact.country)")
>> JOHN SMITH, LONDON, UNITED KINGDOM 

壱・丙 複数の変数とタイプをサポート

前の例題にPropertyWrapperはラップングされる {Property = }で割り当てる var の形でただ一つの値を受けました。
どんな作業を実行する時使用される複数の値を受ける様にもっと複雑な{@ProWrap var :}を実装する事ができます。追加される値は{@ProWrap(ここで) var :}で置きます。

@propertyWrapper
struct MinMaxVal {
    var value: Int
    let max: Int
    let min: Int
    
    init(wrappedValue: Int, max: Int, min: Int) {
        value = wrappedValue
        self.max = max
        self.min = min
    }
    var wrappedValue: Int {
        get{ return value}
        set{
            if newValue > max {
                value = max
            } else if newValue < min {
                value = min
            } else {
                value = newValue
            }
        }
    }
}


struct Demo{
    @MinMaxVal(min: 10, max: 150) var value: Int = 100
}

{init{}}は Wrapper Valueで追加されるminとmaxの値を受け取って実装されます。wrappedValueのsetは値が特定範囲の中であるかどうか検査してその値をminとmaxで割り当てます。
前のpropertyWrapperは次のコードでテストできます。

struct Demo{
    @MinMaxVal(min: 100, max: 200) var value: Int = 100
}

var demo = Demo()
demo.value = 150
print(demo.value)

demo.value = 250
print(demo.value)

このコードを実行するとさ一番目のprint syntaxは150を出力します。なでなら150は許容範囲内に入っているからです。反面、2番目のprint syntaxは200を出力します。なぜならwrapperが最大値を200までしか許容の為です。
現在、実装されたPropertyWrapperはInt var だけで作業します。もし、同じターフの他の var 比較できる全ての変数ターフと一緒に使えるなら有用になるはずです。
幸いにも、PropertyWrapper特定のprotocolを従う全てのターフと一緒に作業ができます。
PropertyWrapperの目的は比較作業をすることで、Foundation frameWorkでふくまれるComparable : Protocolを従う全てのデータターフを対応するように修正する必要があります。
Comparable  : Protocolを従うターフは値が同じか大きいか小さいかを比較するに使用される事ができます。Stifng, Int, Date, DateInterval, Characterみたいな多様なターフがこの : Protocolを従います。

Comparable : Protocolを使用されるためにPropertyWrapperを実装するために宣言部は次の様に修正必要があります。

@propertyWrapper
struct MinMaxVal<V: Comparable> {
    var value: V
    let max: V
    let min: V
    
    init(wrappedValue: V, min: V ,max: V) {
        value = wrappedValue
        self.min = min
        self.max = max
    }
    
    var wrappedValue: V {
.
.
.

この様に修正されたwrapperは前でした様にIntvar でも動作し、Comparable : Protocolを従う方の全てのターフでも使用できます。
次の例題は文字列の値がアルファベットの観点からminとmax範囲の中で入るのかどうかを判断する事です。

struct Demo{
    @MinMaxVal(min: "Apple", max: "Orange") var value: String = ""
}
var demo = Demo()
demo.value = "Banana"
print(demo.value)
>> Banana
demo.value = "Pear"
print(demo.value)
>> Orange <- この値は与えられたAlpabet範囲外なので。。。

同じ様に、このWrapperは Date Object:としても動作します。
次の例題は現在日付と一月の後の日付まで制限しています。

struct DateDemo{
    @MinMaxVal(min: Date(), max: Calendar.current.date(byAdding: .month, value: 1, to: Date())!) var value: Date = Date()
}

次のコードは結果は私たちが作れたwrapperがDate var を持つても動作得ることを示すことです。

var dateDemo = DateDemo()

print(dateDemo.value)

dateDemo.value = Calendar.current.date(byAdding: .day, value: 10, to: Date())!
print(dateDemo.value)

dateDemo.value = Calendar.current.date(byAdding: .month, value: 2, to: Date())!
print(dateDemo.value)

予約 

Swift 5.1で導入されたPropertyWrapperClassStruct宣言内でコードの重複を避けながらアフリprojectのコードを通じて再利用される{var{get,set{}}}Struct{}を使用できる様にします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?