You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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才能监听实例内部的状态变化。

修复方案

需要调整状态管理的方式,具体改动如下:

  1. 让ProximityObserver遵循ObservableObject协议,用@Published标记需要监听的state属性,确保属性变化时能通知视图更新。
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:50:21