SwiftUI中无法从@objc函数修改类属性的问题求助
问题描述
尝试在SwiftUI中捕获距离传感器(ProximitySensor)的活动,创建了ProximityObserver类,试图在通知回调中更新state属性,但执行state = device.proximityState后,state从未改变。相关代码如下:
import SwiftUI import UIKit class ProximityObserver { @State var state = false; @objc func didChange(notification: NSNotification) { print("MyView::ProximityObserver.didChange") if let device = notification.object as? UIDevice { print(device.proximityState) state = device.proximityState print(state) } } } struct ContentView: View { @State var proximityObserver = ProximityObserver() func activateProximitySensor() { print("MyView::activateProximitySensor") if !UIDevice.current.isProximityMonitoringEnabled { UIDevice.current.isProximityMonitoringEnabled = true if UIDevice.current.isProximityMonitoringEnabled { NotificationCenter.default.addObserver(proximityObserver, selector: #selector(proximityObserver.didChange), name: UIDevice.proximityStateDidChangeNotification, object: UIDevice.current) } } } func deactivateProximitySensor() { print("MyView::deactivateProximitySensor") UIDevice.current.isProximityMonitoringEnabled = false NotificationCenter.default.removeObserver(proximityObserver, name: UIDevice.proximityStateDidChangeNotification, object: UIDevice.current) } var body: some View { Text(proximityObserver.state ? "true" : "false" ) .animation(.linear(duration: 20).delay(20), value: proximityObserver.state) .onAppear() { self.activateProximitySensor() } .onDisappear() { self.deactivateProximitySensor() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
日志输出显示:
MyView::ProximityObserver.didChange true false
问题原因
@State属性包装器仅适用于SwiftUI的View结构体内部,不能用于普通类。@State的核心作用是让SwiftUI管理视图的状态,类实例中的@State不会被SwiftUI正确跟踪,赋值操作无法生效。ContentView中用@State存储ProximityObserver实例也是错误用法:@State设计用于值类型,引用类型需要用@ObservedObject或@StateObject来管理,这样SwiftUI才能监听实例内部的状态变化。
修复方案
需要调整状态管理的方式,具体改动如下:
- 让
ProximityObserver遵循ObservableObject协议,用@Published标记需要监听的state属性,确保属性变化时能通知视图更新。 - 在
ContentView中用@StateObject(iOS 14+)持有ProximityObserver实例,确保SwiftUI能监听其内部状态变化并管理实例生命周期。
修改后的完整代码:
import SwiftUI import UIKit class ProximityObserver: ObservableObject { @Published var state = false @objc func didChange(notification: NSNotification) { print("MyView::ProximityObserver.didChange") if let device = notification.object as? UIDevice { print(device.proximityState) state = device.proximityState print(state) } } } struct ContentView: View { @StateObject private var proximityObserver = ProximityObserver() func activateProximitySensor() { print("MyView::activateProximitySensor") if !UIDevice.current.isProximityMonitoringEnabled { UIDevice.current.isProximityMonitoringEnabled = true if UIDevice.current.isProximityMonitoringEnabled { NotificationCenter.default.addObserver(proximityObserver, selector: #selector(proximityObserver.didChange), name: UIDevice.proximityStateDidChangeNotification, object: UIDevice.current) } } } func deactivateProximitySensor() { print("MyView::deactivateProximitySensor") UIDevice.current.isProximityMonitoringEnabled = false NotificationCenter.default.removeObserver(proximityObserver, name: UIDevice.proximityStateDidChangeNotification, object: UIDevice.current) } var body: some View { Text(proximityObserver.state ? "true" : "false" ) .animation(.linear(duration: 20).delay(20), value: proximityObserver.state) .onAppear() { activateProximitySensor() } .onDisappear() { deactivateProximitySensor() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
关键改动说明
ProximityObserver继承ObservableObject并使用@Published:@Published会在属性值变化时自动发送通知,让监听该对象的SwiftUI视图触发更新。ContentView使用@StateObject:@StateObject专门用于创建和管理引用类型的生命周期,确保视图在整个生命周期内复用同一个ProximityObserver实例,且能响应其@Published属性的变化。若需兼容iOS 13,可替换为@ObservedObject,但需注意实例的创建时机和生命周期管理。
内容的提问来源于stack exchange,提问作者user1329928
相关产品推荐
相关产品推荐

