swift 从ObservableObject+合并迁移到Observable的问题

xdnvmnnf  于 2023-09-29  发布在  Swift
关注(0)|答案(2)|浏览(88)

我面临着从ObservableObject+合并迁移到Observable的问题。
苹果有一个很棒的迁移指南,它甚至没有提出任何问题。但是没有关于如何从合并保存代码的信息。
下面是一个使用ObservableObject协议的类的例子:

class ViewModel: ObservableObject {
    @Published var scale: CGFloat = 1.0
    var cancellable: Set<AnyCancellable> = []
    
    init() {
        $scale
            .dropFirst()
            .debounce(for: 0.2, scheduler: RunLoop.main)
            .sink { value in
                Task(){ 
                      // Code
                }
            }
            .store(in: &cancellable)
    }
}

问题如下-如何保存与合并相关的结构,如.sink{},.debounce(),.store()等?
我在文件里找不到。到目前为止,我只看到使用.get {} .set{}绘制功能
这些东西非常方便,我在几个商业项目中使用它们。没有这一点,就很难维持业务逻辑的正常运行。
也许有人遇到过这种情况。

a0x5cqrl

a0x5cqrl1#

首先也是最重要的一点,如果您喜欢模式的语义并正在使用它,那么您没有理由必须给予@PublishedObservableObject。这些技术是使用Combine作为实现细节构建的,您似乎正在使用它。
新的@Observable确实有一个稍微不同的模型。我找不到一种方法来扩展宏,但它看起来像是直接将ObservationRegistrar注入到类中,我怀疑它级联调用通知链中的类的注册器,而不是依赖于Combine observable。
您可能还需要考虑更明确地使用Combine。意识到这只是示例代码,示例中的@Published属性可以替换为CurrentValueSubject,以获得大致相同的效果。

cngwdvgl

cngwdvgl2#

您可以使用Combine,但不能使用@Published,因为它是一个属性 Package 器。
你可以做这样的事。。

@Observable
class CombineObservable{
    var scale: CurrentValueSubject<Double, Never> = .init(0)
    var cleanScale: Double = -1
    var cancellable: Set<AnyCancellable> = []

    init() {
            scale
            .dropFirst()
            .debounce(for: 0.2, scheduler: RunLoop.main)
            .sink { [ self] value in
                Task(){
                    print("Task")
                      // Code
                    cleanScale = value
                }
            }
            .store(in: &cancellable)
    }
}

但是那些像sink中的浮动Task可能会有很大的问题,所以我会选择下面这样的东西。

import SwiftUI
import Combine
struct CombineForiOS17: View {
    @State private var co = CombineObservable()
    @State private var current: Double = 0
    var body: some View {
        List {
            //To mock changes that need debouncing.
            Section("Sample Publish behavior") {
                Text(current, format: .number)
                Slider(value: $current, in: -100...100)
                    .task(id: current) {
                        co.scale.send(current)
                    }
            }
            Section("Debounced value") {
                Text(co.debouncedScale, format: .number)
                    .task(id: co.debouncedScale) { //When the new scale is received do something...
                        //Do something async/await when the debounced value is received
                        print("doing something")
                    }
            }
            //Subscribe to changes (SwiftUI substitute for AnyCancellable)
            .onReceive(co.scale
                .dropFirst()
                .debounce(for: 0.2, scheduler: DispatchQueue.main), perform: { newValue in
                    //Set the new debounced value in a synchronous context.
                    co.debouncedScale = newValue
                })
            
            
        }
    }
}

#Preview {
    CombineForiOS17()
}
@Observable
class CombineObservable{
    //Combine
    var scale: CurrentValueSubject<Double, Never> = .init(0)
    //Final result for the View
    var debouncedScale: Double = -1
    
    init() { }
}

相关问题