我正在尝试制作一个类似于 的属性包装器Combine(Published满足我的项目需求),但能够通过向发布者发送存储在 中的值来修改包装的属性projectedValue,如下所示:
// in class
@PublishedMutable var foo = "foo"
$foo.send("bar")
// ...
Run Code Online (Sandbox Code Playgroud)
这是属性包装器的代码:
@propertyWrapper
struct PublishedMutable<Value> {
static subscript<T: ObservableObject>(
_enclosingInstance instance: T,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
) -> Value {
get {
instance[keyPath: storageKeyPath].storage
}
set {
let publisher = instance.objectWillChange
// This assumption is definitely not safe to make in
// production code, but it's fine for this demo purpose:
(publisher as? ObservableObjectPublisher)?.send()
instance[keyPath: storageKeyPath].storage = …Run Code Online (Sandbox Code Playgroud) swift combine property-wrapper property-wrapper-published swift-property-wrapper
我一直在尝试使用onKeyPressSwiftUI 5 中的新功能。但是,更新到@Published在处理程序中更新可观察对象的属性会产生警告“不允许从视图更新中发布更改,这将导致未定义的行为。”
注意,在实践中我还没有看到任何实际错误,但 Xcode 在控制台中记录了大量红色警告和紫色运行时问题。
简单的复制;可以通过按钮修改,也可以在本地修改@State而不提示;但是,修改该@Published属性会onKeyPress产生警告。
import SwiftUI
@MainActor
class ExampleService: ObservableObject {
@Published var text = ""
}
struct ContentView: View {
@StateObject var service = ExampleService()
@State var localText = ""
var body: some View {
VStack {
Button {
// This is fine
service.text += "!"
} label: {
Text("Press Me")
}
Label("Example Focusable", systemImage: "arrow.right")
.focusable()
.onKeyPress { action in
// XCode whines about "Publishing …Run Code Online (Sandbox Code Playgroud) 在我的视图模型中,我有这个属性和方法:
@Published var cats: [Cat] = [] //this gets populated later
Run Code Online (Sandbox Code Playgroud)
当我更新其中一只猫时:
func updateCatQuantity(_ cat:Cat, qty: Int) {
if let index = cats(of: cat) {
cats[index].quantity = qty
}
}
Run Code Online (Sandbox Code Playgroud)
视图不会刷新。didSetoncats不会被调用。Cat我认为这与类而不是结构这一事实有关。它的定义如下:
class Cat: BaseMapperModel, Identifiable, Hashable {
static func == (lhs: Cat, rhs: Cat) -> Bool {
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}
var id = UUID()
var title: String = ""
var quantity: Int = 0
func hash(into hasher: inout Hasher) {
hasher.combine(id)
} …Run Code Online (Sandbox Code Playgroud)