Swift 13 Property Wrapper 財産の上紙せせ

此れは、Swift5.1から出てきて `Class{}`と`Struct{}`の実装部に`{var{get{}}}`と`{var{set{}}}`そしてcomputed property コードの重複を減らす方法を提供します。
![Screenshot 2023-10-21 at 9.55.05 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/359cd25e-4a0a-7fe7-fcf6-75910d182d4d.png)

# 十三・壱　Property Wrapper
## 壱・甲　Property Wrapperについて
`Class`と`Struct` `{Instance{}}`にある`{Property = }`で値を割り当うとか、
接近する時値を保存するとか、読み込む前に変更作業とValidationをする時が度々あります。実はcomputed propertyとしてする事ができます。
だが、様々な `Class`と`Struct`で生成されたComputed Propertyは似た様なパータンを持っている場合にが頻繁にあります。
Swift5.1前には、computedPropertyを共有する唯一な方法はいちいち`Class`と`Struct`で含まるだけでした。
その短所を補完するために**PropertyWrapper**を導入しました。
此れは基本的に**computedPropertyの機能を個別`Class`と`Struct`と分離**できるようにして、アフリコードで再利用できる様にします。
## 壱・乙　Property Wrapper例題
都市の名前を保存するString Propertyを持っている`Struct{}`あるとしよう。
```swift
struct Address{
    var city: String
}
```
使用者が都市の名前をどうやって入力するかはかかわらずに大文字に保存されると、次の様にComputedPropertyを`Struct{}`で追加できます。
```swift
struct Address{
    private var cityname: String = ""
    
    var city: String {
        get {cityname}
        set {cityname = newValue.uppercased()}
    }
}
```
都市の名前が`{Property = }`で割り当てられると、演算プロパティの`set`がprivate cityname `var    `で値を保存する前に大文字に変更する事になる
今作った`Struct{}`をテストする為に次の様にします。
```swift
var address = Address()

address.city = "London"
print(address.city)
>> LONDON
```
演算フロパティは都市名前の文字を大文字に変更されました。
もし、この様な作業が他の `Struct`とか`Class`でひつよなら、今のコードをコピーして必要なところで貼り付ける方法もあります。
だが、今の例題はコードの多さが少ないからそうなるですけど、大量のコードと複雑な演算がある場合には適度はないと思います。
演算フロパティを使用する代わりに、*このロジックをフロパティラッパーで実装できます。*
例えば、次の宣言部は文字列を大文字で変更すると設計されたFixCaseというフロパティラッパーを実装できます。
```swift
@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支持者を付けてばいいです。
```swift
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 :}`で置きます。
```swift
@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は次のコードでテストできます。
```swift
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は許容範囲内に入っているからです。反面、２番目の`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`を実装するために宣言部は次の様に修正必要があります。
```swift
@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`は前でした様にInt`var    `でも動作し、Comparable  `: Protocol`を従う方の全てのターフでも使用できます。
次の例題は文字列の値がアルファベットの観点からminとmax範囲の中で入るのかどうかを判断する事です。
```swift
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:`としても動作します。
次の例題は現在日付と一月の後の日付まで制限しています。
```swift
struct DateDemo{
    @MinMaxVal(min: Date(), max: Calendar.current.date(byAdding: .month, value: 1, to: Date())!) var value: Date = Date()
}
```
次のコードは結果は私たちが作れたwrapperがDate `var    `を持つても動作得ることを示すことです。
```swift
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で導入された`PropertyWrapper`は`Class`と`Struct`宣言内でコードの重複を避けながらアフリprojectのコードを通じて再利用される`{var{get,set{}}}`の`Struct{}`を使用できる様にします。