@Published 不能按预期使用环境对象和嵌套的 ObservableObejct
@Published doesn't work as expected with enviornment object and nested ObservableObejct
假设我有 UserSettings
EnviornmentObject
,其中一个属性是 class,问题是当我更改 class 的值时,EnviornmentObject
不会发布这些更改。我明白为什么,但我似乎找不到解决方法。
这里是显示问题的简化代码:
struct TestView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
ZStack {
Text("test: \(self.settings.ob.val)")
VStack {
// This is the only one that works and that makes sense, it changes the entire object
Button(action: {
self.settings.changeOb(to: testOb(val: "1"))
}) {
Text("Change object")
}
// From here on nothing works, I tried different ways to change the object value
Button(action: {
self.settings.ob.changeVal(to: "2")
}) {
Text("Change object's val")
}
Button(action: {
self.settings.changeVal(to: "3")
}) {
Text("Change object's val V2")
}
Spacer()
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
return ZStack {
TestView().environmentObject(UserSettings(ob: testOb("abc")))
}
}
}
class testOb: ObservableObject {
@Published private(set) var val: String
init(val: String) {
self.val = val
}
func changeVal(to: String) {
self.val = to
}
}
class UserSettings: ObservableObject {
@Published private(set) var ob: testOb
init(ob: testOb) {
self.ob = ob
}
func changeOb(ob: testOb) {
self.ob = ob
}
func changeVal(to: String) {
self.ob.val(to: to)
}
}
我终于能够修复它,问题是 Apple 不支持嵌套的 ObesrvableObject
s 以及许多重要的功能(这很可悲,但无论如何),但据我所知,这是他们的议程。
解决方案是每次我的对象发生变化时我都必须手动通知,你拥有的对象越多,这可能会很痛苦。
要通知我们首先需要导入 Combine
这样我们就可以使用 AnyCancellable
负责通知。
这是更新后的代码:
// FIRST CHANGE
import Combine
struct TestView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
ZStack {
Text("test: \(self.settings.ob.val)")
VStack {
// This is the only one that works and that makes sense, it changes the entire object
Button(action: {
self.settings.changeOb(to: testOb(val: "1"))
}) {
Text("Change object")
}
// From here on nothing works, I tried different ways to change the object value
Button(action: {
self.settings.ob.changeVal(to: "2")
}) {
Text("Change object's val")
}
Button(action: {
self.settings.changeVal(to: "3")
}) {
Text("Change object's val V2")
}
Spacer()
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
return ZStack {
TestView().environmentObject(UserSettings(ob: testOb("abc")))
}
}
}
class testOb: ObservableObject {
@Published private(set) var val: String
init(val: String) {
self.val = val
}
func changeVal(to: String) {
self.val = to
}
}
class UserSettings: ObservableObject {
@Published private(set) var ob: testOb
// SECOND CHANGE, this is responsible to notify on changes
var anyCancellable: AnyCancellable? = nil
init(ob: testOb) {
self.ob = ob
// THIRD CHANGE, initialize our notifier
anyCancellable = self.ob.objectWillChange.sink { (_) in
self.objectWillChange.send()
}
}
func changeOb(ob: testOb) {
self.ob = ob
}
func changeVal(to: String) {
self.ob.val(to: to)
}
}
尝试这样的事情:
class UserSettings: ObservableObject {
@Published var ob: testOb{
willSet{
observer.cancel()
}
didSet{
observer = ob.objectWillChange.sink(){self.objectWillChange.send()}
}
}
var observer: AnyCancellable!
init(ob: testOb) {
self.ob = ob
self.observer = nil
self.observer = ob.objectWillChange.sink(){self.objectWillChange.send()}
}
func sendChange(){
}
func changeOb(ob: testOb) {
self.ob = ob
}
func changeVal(to: String) {
self.ob.changeVal(to: to)
}
deinit {
observer.cancel()
}
}
@Published
是发送通知,不是监听
或者您可以将弱 link 存储到子对象中的父对象,并在子对象的 willSet{}
中调用 parent.objectWillChange.send()
。
假设我有 UserSettings
EnviornmentObject
,其中一个属性是 class,问题是当我更改 class 的值时,EnviornmentObject
不会发布这些更改。我明白为什么,但我似乎找不到解决方法。
这里是显示问题的简化代码:
struct TestView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
ZStack {
Text("test: \(self.settings.ob.val)")
VStack {
// This is the only one that works and that makes sense, it changes the entire object
Button(action: {
self.settings.changeOb(to: testOb(val: "1"))
}) {
Text("Change object")
}
// From here on nothing works, I tried different ways to change the object value
Button(action: {
self.settings.ob.changeVal(to: "2")
}) {
Text("Change object's val")
}
Button(action: {
self.settings.changeVal(to: "3")
}) {
Text("Change object's val V2")
}
Spacer()
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
return ZStack {
TestView().environmentObject(UserSettings(ob: testOb("abc")))
}
}
}
class testOb: ObservableObject {
@Published private(set) var val: String
init(val: String) {
self.val = val
}
func changeVal(to: String) {
self.val = to
}
}
class UserSettings: ObservableObject {
@Published private(set) var ob: testOb
init(ob: testOb) {
self.ob = ob
}
func changeOb(ob: testOb) {
self.ob = ob
}
func changeVal(to: String) {
self.ob.val(to: to)
}
}
我终于能够修复它,问题是 Apple 不支持嵌套的 ObesrvableObject
s 以及许多重要的功能(这很可悲,但无论如何),但据我所知,这是他们的议程。
解决方案是每次我的对象发生变化时我都必须手动通知,你拥有的对象越多,这可能会很痛苦。
要通知我们首先需要导入 Combine
这样我们就可以使用 AnyCancellable
负责通知。
这是更新后的代码:
// FIRST CHANGE
import Combine
struct TestView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
ZStack {
Text("test: \(self.settings.ob.val)")
VStack {
// This is the only one that works and that makes sense, it changes the entire object
Button(action: {
self.settings.changeOb(to: testOb(val: "1"))
}) {
Text("Change object")
}
// From here on nothing works, I tried different ways to change the object value
Button(action: {
self.settings.ob.changeVal(to: "2")
}) {
Text("Change object's val")
}
Button(action: {
self.settings.changeVal(to: "3")
}) {
Text("Change object's val V2")
}
Spacer()
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
return ZStack {
TestView().environmentObject(UserSettings(ob: testOb("abc")))
}
}
}
class testOb: ObservableObject {
@Published private(set) var val: String
init(val: String) {
self.val = val
}
func changeVal(to: String) {
self.val = to
}
}
class UserSettings: ObservableObject {
@Published private(set) var ob: testOb
// SECOND CHANGE, this is responsible to notify on changes
var anyCancellable: AnyCancellable? = nil
init(ob: testOb) {
self.ob = ob
// THIRD CHANGE, initialize our notifier
anyCancellable = self.ob.objectWillChange.sink { (_) in
self.objectWillChange.send()
}
}
func changeOb(ob: testOb) {
self.ob = ob
}
func changeVal(to: String) {
self.ob.val(to: to)
}
}
尝试这样的事情:
class UserSettings: ObservableObject {
@Published var ob: testOb{
willSet{
observer.cancel()
}
didSet{
observer = ob.objectWillChange.sink(){self.objectWillChange.send()}
}
}
var observer: AnyCancellable!
init(ob: testOb) {
self.ob = ob
self.observer = nil
self.observer = ob.objectWillChange.sink(){self.objectWillChange.send()}
}
func sendChange(){
}
func changeOb(ob: testOb) {
self.ob = ob
}
func changeVal(to: String) {
self.ob.changeVal(to: to)
}
deinit {
observer.cancel()
}
}
@Published
是发送通知,不是监听
或者您可以将弱 link 存储到子对象中的父对象,并在子对象的 willSet{}
中调用 parent.objectWillChange.send()
。