SwiftUI中ObservedObject无法获取点击事件的问题排查
问题:ObservedObject无法响应点击事件更新UI
点击AdsView中的图片后,尝试修改network.networkObserver.sucess状态,但主ContentView的Text无法同步更新,相关代码如下:
ContentView 代码
struct ContentView: View { @StateObject var network = Network() var body: some View { VStack { SecondView(network: network) Text(self.network.networkObserver.sucess?.description ?? "Nil") } } }
AdsView(即SecondView)代码
public struct AdsView: View { @State private var banner: Model? @State private var image: UIImage? @State private var scale: Double = 1.0 @ObservedObject var network: Network public var body: some View { Group { if let image = image { Text("AdSDK mockup. Click on image") Image(uiImage: image) .resizable() .scaledToFit() .scaleEffect(scale) .gesture ( TapGesture() .onEnded { _ in self.scale -= 0.1 network.networkObserver.sucess = network.networkObserver.sucess ?? false ? false : true } ) } else { Rectangle() .background(Color.red) } } } }
Network 类代码(自定义库中)
public class Network: ObservableObject { @Published public var adImage: UIImage? @Published public var networkObserver = NetworkObserver() public init() { } public func getImage(for imageURL: String) async throws { } }
NetworkObserver 类代码
public class NetworkObserver { public var sucess: Bool? public var error: RequestError? public init() { } }
错误原因分析
- NetworkObserver未实现可观察机制:
sucess属性无@Published标记,属性变化无法触发SwiftUI视图更新。 - 引用类型属性更新未触发通知:Network类中
networkObserver虽标记@Published,但它是class类型(引用类型),修改内部sucess属性时,networkObserver自身引用未改变,因此@Published不会发送更新通知。 - 三目运算符语法歧义:
network.networkObserver.sucess ?? false ? false : true优先级混乱,逻辑不符合预期,需添加括号明确执行顺序。
解决方案
方案一:让NetworkObserver成为可观察对象(推荐)
修改NetworkObserver类,使其遵循ObservableObject并标记内部属性为@Published:
public class NetworkObserver: ObservableObject { @Published public var sucess: Bool? @Published public var error: RequestError? public init() { } }
调整Network类,移除networkObserver的@Published标记(自身已是ObservableObject,内部属性变化会自动发通知):
public class Network: ObservableObject { @Published public var adImage: UIImage? public var networkObserver = NetworkObserver() // 去掉@Published public init() { } public func getImage(for imageURL: String) async throws { } }
修正AdsView中的逻辑,简化状态切换代码:
TapGesture() .onEnded { _ in self.scale -= 0.1 // 简化sucess状态切换逻辑 network.networkObserver.sucess = !(network.networkObserver.sucess ?? false) }
方案二:手动发送更新通知(备选)
若无法修改NetworkObserver结构,可在修改sucess后手动触发Network的更新通知:
TapGesture() .onEnded { _ in self.scale -= 0.1 // 手动发送更新通知 network.objectWillChange.send() // 修正三目运算符优先级 network.networkObserver.sucess = (network.networkObserver.sucess ?? false) ? false : true }
内容的提问来源于stack exchange,提问作者V D Purohit
相关产品推荐
相关产品推荐

