swiftUI 属性包装 @State @ObservableObject @EnvironmentObject

//
//  Converter.swift
//  TestUIKitApp
//
//  Created by bob bob on 2021/3/10.
//

import Foundation
import SwiftUI
/*
 @propertyWrapper 属性包装,可以理解为装饰器模式,比如 @State,@Binding,@ObjectBinding,@EnvironmentObject
1 init(initialValue:),wrappedValue 和 projectedValue 构成了一个 propertyWrapper 最重要的部分
 不过 initialValue 这个参数名相对特殊:当它出现在 init 方法的第一个参数位置时,编译器将允许我们在声明的时候直接为 @State var value 进行赋值。
 2 使用美元符号前缀 ($) 访问 ,其实访问的是 projectedValue 属性,不加$访问的是  wrappedValue 值。
 3 在State 中,这个属性返回一个 Binding 类型的值,通过遵守BindingConvertible,State 暴露了修改其内部存储的方法,这也就是为什么传递 Binding 具有引用语义的原因。
 下面是模仿@State写的一个美元转换装饰器
 */
@propertyWrapper
struct Converter1{
    let from:String
    let to:String
    let rate:Double
    
    var value:Double
    var wrappedValue:String{
        get{
            "\(from)\(value)"
        }
        set{
            value = Double(newValue) ?? -1
        }
    }
    
    var projectedValue:String{
        return "\(to)\(value * rate)"
    }
    
    init(initialValue:String,
         from:String,
         to:String,
         rate:Double
    ) {
        self.rate = rate
        self.value = 0
        self.from = from
        self.to = to
        self.wrappedValue = initialValue
    }
    
    
}

struct TestWraper {
    @State var myname = ""
    @Converter1(initialValue: "100", from: "USD", to: "CNY", rate: 6.88)
    var usd_cny
    
    @Converter1(initialValue: "100", from: "CNY", to: "EUR", rate: 0.13)
    var cny_eur
    
    func test1(){
        print("\(usd_cny)=\($usd_cny)")
        print("\(cny_eur)=\($cny_eur)")
    }
    /*
     USD100.0=CNY688.0
     CNY100.0=EUR13.0
     */
}

ObservableObject

//
//  ObServContentView.swift
//  Calculator
//
//  Created by bob bob on 2021/3/10.
//  Copyright © 2021 OneV's Den. All rights reserved.
//

import SwiftUI
class Conect:ObservableObject{
    var name:String
    @Published var age:Int = 0
    var num:Int{
        willSet{
            objectWillChange.send()
        }
    }
    init(name:String,num:Int) {
        self.name = name
        self.num = num
        for i in 1...10{
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
                self.age += 1
            }
        }
    }
}
struct ObServContentView: View {
    @ObservedObject var  john = Conect(name: "Bob",num: 0)
    var body: some View {
        Text("Age:\(john.age)")
        Text("Num:\(john.num)")
        Button(action: {
            john.num += 1
        }, label: {
            Text("Button")
        })
    }
}

struct ObServContentView_Previews: PreviewProvider {
    static var previews: some View {
        ObServContentView()
    }
}

EnvironmentObject


import SwiftUI

class User: ObservableObject {
    @Published var name = "Bob"
}
struct MEditView:View {
    @EnvironmentObject var user:User
    var body: some View{
        TextField("Name", text: $user.name)
    }
}
struct NEditView:View {
    @EnvironmentObject var user:User
    var body: some View{
        TextField("Name", text: $user.name)
    }
}
struct EnvironmentContentView: View {
    var user = User()
    var num:Int = 0
    var body: some View {
        VStack{
            //不要忘记环境中的实例,否则会崩溃
            MEditView().environmentObject(user)
            NEditView().environmentObject(user)
            Button(action: {
                user.name = user.name.appending("\(num)")
            }, label: {
                Text("NeditBtn")
            })
        }
    }
}

struct EnvironmentContentView_Previews: PreviewProvider {
    static var previews: some View {
        EnvironmentContentView()
    }
}


版权声明:本文为bobbob32原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。