标签: property-wrapper

UserDefault 属性包装器不保存值低于 iOS 13 的 iOS 版本

我正在使用属性包装器来保存我的用户默认值。在 iOS 13 设备上,此解决方案效果很好。但是,在 iOS 11 和 iOS 12 上,这些值不会保存到用户默认值中。我读到属性包装器向后兼容,所以我不知道为什么这不适用于较旧的 iOS 版本。

这是属性包装器:

@propertyWrapper
struct UserDefaultWrapper<T: Codable> {
    private let key: String
    private let defaultValue: T

    init(key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            guard let data = UserDefaults.standard.object(forKey: key) as? Data else {
                // Return defaultValue when no data in UserDefaults
                return defaultValue
            }

            // Convert data to the desire data type
            let value = try? JSONDecoder().decode(T.self, from: data) …
Run Code Online (Sandbox Code Playgroud)

ios swift swift5 property-wrapper

6
推荐指数
1
解决办法
1159
查看次数

@EnvironmentObject 和 @ObservedObject 有什么区别?

我一直在阅读 SwiftUI 中的属性包装器,我看到它们做得很好,但我真正不明白的一件事是@EnvironmentObject@ObservedObject之间的区别。

从我到目前为止所学到的,我看到@EnvironmentObject在我们的应用程序的各个地方都需要一个对象时使用,但我们不需要通过所有这些地方传递它。例如,如果我们有层次结构 A -> B -> C -> D 并且对象是在 A 处创建的,那么它会保存在环境中,以便我们可以将它直接从 A 传递到 D,如果 D 需要的话。

如果我们使用在 A 创建并需要传递给 D 的@ObservedObject,那么我们也需要通过 B 和 C。

但我仍然不知道如何决定使用哪一个。以下是我制作的 2 个示例项目:

struct ContentView2: View {
 
   var order = Order2()

   var body: some View {
      VStack {
           EditView2()
           DisplayView2()
       }
       .environmentObject(order)
   }
}
struct EditView2: View {
   @EnvironmentObject var user: Order2
 
   var body: some View {
       HStack{
       TextField("Fruit", text: $user.item)
       }
   }
}
struct …
Run Code Online (Sandbox Code Playgroud)

swiftui property-wrapper observedobject environmentobject

6
推荐指数
1
解决办法
1510
查看次数

为计算属性添加@Published 行为

我正在尝试制作一个ObservableObject具有包装UserDefaults变量的属性。

为了符合ObservableObject,我需要用 包装属性@Published。不幸的是,我不能将它应用于计算属性,因为我用于UserDefaults值。

我怎么能让它工作?我必须做什么才能实现@Published行为?

swift swiftui combine property-wrapper

5
推荐指数
3
解决办法
3633
查看次数

如何实现自定义属性包装器,它将发布 SwiftUI 的更改以重新呈现其视图

尝试实现一个自定义属性包装器,它也会以相同的方式发布其更改@Publish。例如,允许我的 SwiftUI 使用我的自定义包装器接收对我的属性的更改。

我的工作代码:

import SwiftUI

@propertyWrapper
struct MyWrapper<Value> {
    var value: Value

    init(wrappedValue: Value) { value = wrappedValue }

    var wrappedValue: Value {
        get { value }
        set { value = newValue }
    }
}

class MySettings: ObservableObject {
    @MyWrapper
    public var interval: Double = 50 {
        willSet { objectWillChange.send() }
    }
}

struct MyView: View {
    @EnvironmentObject var settings: MySettings

    var body: some View {
        VStack() {
            Text("\(settings.interval, specifier: "%.0f")").font(.title)
            Slider(value: $settings.interval, in: 0...100, step: 10) …
Run Code Online (Sandbox Code Playgroud)

swift swiftui property-wrapper

5
推荐指数
1
解决办法
734
查看次数

在 SwiftUI 中,应用程序在滑回一半时冻结且没有任何警告,但在完成之前释放

以下代码重现了该错误:

import SwiftUI

struct ContentView: View {
    @State private var number: Int = 5
    var body: some View {
        NavigationView() {
            VStack(spacing: 20) {
                NavigationLink(destination: SecondView(bottles: $number)) {
                    Text("Click me")
                }
            }
        }
    }
}

struct SecondView: View {
    @Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
    @State private var color: UIColor = .black
    @Binding var bottles: Int

    var body: some View {
        Text("I have \(bottles) in my bag")
            .foregroundColor(Color(color))
            .navigationBarTitle(Text("Water Bottle"))
            .navigationBarItems(trailing:
                Button("Click") {
                    self.someFunction()
                }
        )
    }

    func someFunction() {
        if …
Run Code Online (Sandbox Code Playgroud)

ios swift swiftui ios-navigationview property-wrapper

5
推荐指数
1
解决办法
2484
查看次数

如何在 Swift 中测试和模拟属性包装器?

假设我有一个使用 的属性包装器的非常常见的用例UserDefaults

@propertyWrapper
struct DefaultsStorage<Value> {
    private let key: String
    private let storage: UserDefaults
    
    var wrappedValue: Value? {
        get {
            guard let value = storage.value(forKey: key) as? Value else {
                return nil
            }
            
            return value
        }
        
        nonmutating set {
            storage.setValue(newValue, forKey: key)
        }
    }
    
    init(key: String, storage: UserDefaults = .standard) {
        self.key = key
        self.storage = storage
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在声明一个对象,该对象将保存存储在UserDefaults.

struct UserDefaultsStorage {
    @DefaultsStorage(key: "userName")
    var userName: String?
}
Run Code Online (Sandbox Code Playgroud)

现在,当我想在某个地方使用它时,比如说在视图模型中,我会有这样的东西。

final class ViewModel {
    func getUserName() …
Run Code Online (Sandbox Code Playgroud)

ios swift property-wrapper

5
推荐指数
1
解决办法
1978
查看次数

SwiftUI 我可以使用 Binding 获取带有 @Binding 属性包装器的自定义绑定吗?

如何在 SwiftUI 视图上使用Binding(get: { }, set: { })带有@Binding属性的自定义绑定。我已经成功地将此自定义绑定与@State变量一起使用,但不知道如何将其应用于@Binding子视图初始值设定项。我需要它来观察@Binding父类分配给属性的更改,以便执行带有一些副作用的代码!

binding swiftui property-wrapper

4
推荐指数
1
解决办法
3584
查看次数

SwiftUI 中的可选 @ObservableObject

我想在 SwiftUI 中有一个可选的 @ObservedObject 但我一直收到编译时错误。

Property type 'AModel?' does not match that of the 'wrappedValue' property of its wrapper type 'ObservedObject'
Run Code Online (Sandbox Code Playgroud)

这是一些最小的可重现代码。

import SwiftUI

public struct AView: View {
    
    //MARK: View Model
    //Error thrown here.
    @ObservedObject var model: AModel?
    
    //MARK: Body
    public var body: some View {
        Text("\(model?.value ?? 0)")
    }
    
    //MARK: Init
    public init() {
        
    }
    
}

class AModel: ObservableObject {
    let value: Int = 0
}
Run Code Online (Sandbox Code Playgroud)

ios swift swiftui property-wrapper

4
推荐指数
1
解决办法
818
查看次数

在 SwiftUI 中使用另一个 @State 属性值初始化 @State 属性

我正在尝试根据另一个值获取进度条的进度值。这两个变量(waterQuantity 和进度)都在属性包装@State中

这是我的代码:

struct CircularProgressBar: View {
@State var waterQuantity: Int
@State var progress: Float = (1 + (Float(waterQuantity)/Float(1500))) * 100

var body: some View {
    ZStack {
        Circle()
            .foregroundColor(.white)
            .padding(25)
            .overlay(
                Circle()
                    .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                    .stroke(style: StrokeStyle(lineWidth: 25
                        , lineCap: .round, lineJoin: .round))
                    .foregroundColor(Color.blue)
                    .rotationEffect(Angle(degrees: 270.0))
                    .animation(.linear)
                    .padding(50)
        )
        
        VStack {
            Text(String(format: "%.0i mL", 500))
                .font(.largeTitle)
                .bold()
                .foregroundColor(Color("bgStart"))
            Text("1500 mL")
                .foregroundColor(.gray)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我无法使用另一个尚未初始化的变量来初始化进度。我尝试使用 init() 和 mutating func 传递值,但这些解决方案都不适合我

swift swiftui property-wrapper

3
推荐指数
1
解决办法
1491
查看次数

如何将枚举集成到 propertyWrapped UserDefault 中

下面的结构适用于基本数据类型,例如IntStringDouble等,有没有办法使其适用于枚举,这样我就不必使用 rawValues 进行手动解析?

@propertyWrapper
struct Storage<T> {
  let objectName: String
  let defaultValue: T
  let defaults: UserDefaults

  init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
    self.objectName = objectName
    self.defaultValue = defaultValue
    self.defaults = defaults
  }

  var wrappedValue: T {
    get { return self.defaults.object(forKey: self.objectName) as? T ?? self.defaultValue }
    set { self.defaults.set(newValue, forKey: self.objectName) }
  }
}
Run Code Online (Sandbox Code Playgroud)

目前我的解决方法是将对象包装在枚举的另一个 getter 和 setter 中,如下所示。

enum SomeType: String {
  case foo, bar, baz
}


class Defaults …
Run Code Online (Sandbox Code Playgroud)

enums swift property-wrapper

2
推荐指数
1
解决办法
1193
查看次数