SwiftUI中@ObservedObject赋值报错:Cannot assign to property: 'self' is immutable
SwiftUI中refreshable闭包无法赋值ObservedObject的解决方法
错误原因
- SwiftUI的
refreshable闭包默认捕获不可变的self,无法直接修改视图结构体的属性 @ObservedObject用于接收父视图传递的ObservableObject实例,视图自身创建的ObservableObject应该使用@StateObject- 直接重新创建
DataSource实例不是最优做法,应该通过调用实例方法刷新数据
解决方法
方案一:修正属性包装器并允许闭包修改实例
将@ObservedObject改为@StateObject,@StateObject支持在闭包中直接赋值更新实例:
struct ContentView: View { @State var editMode: EditMode = .inactive // 改用@StateObject管理视图自身创建的ObservableObject @StateObject var accept = DataSource() var body: some View { VStack { List { ForEach(accept.accepted) { acceptedItem in Text(acceptedItem.number) .bold() .font(.title2) Text("\(acceptedItem.Carrier)") .font(.title3) let que = acceptedItem.events[0] Text("\(que.description)") .font(.title3) } } .refreshable { // 重新创建DataSource实例并赋值 accept = DataSource() } } } }
方案二:给DataSource添加刷新方法(推荐)
复用现有实例刷新数据,避免重复创建实例带来的资源浪费:
- 修改
DataSource类,添加刷新方法并处理旧数据和重复请求:
class DataSource: ObservableObject { @Published var accepted = [Accepted]() private var cancellable: AnyCancellable? init() { gettrackinfoTrack() } // 添加刷新方法:先清空旧数据,再重新请求 func refresh() { accepted.removeAll() gettrackinfoTrack() } func gettrackinfoTrack() { cancellable?.cancel() // 取消之前的请求,避免重复请求导致的数据混乱 cancellable = giphyProvider.requestPublisher(.gettrackinfo) .mapString() .sink(receiveCompletion: { completion in guard case let .failure(error) = completion else { return } print("查询错误:\(String(describing: error.errorDescription))") }, receiveValue: { response in guard let data = response.data(using: .utf8) else { return } if let json = try? JSON(data: data) { let context = json["data"]["accepted"] for (_, subJson) in context { if let acceptedItem = Accepted.accepted_Build(json: subJson, events: Question.build(json: subJson)!) { self.accepted.append(acceptedItem) } } } }) } }
- 修改ContentView的
refreshable闭包,直接调用实例的刷新方法:
struct ContentView: View { @State var editMode: EditMode = .inactive @StateObject var accept = DataSource() var body: some View { VStack { List { ForEach(accept.accepted) { acceptedItem in Text(acceptedItem.number) .bold() .font(.title2) Text("\(acceptedItem.Carrier)") .font(.title3) let que = acceptedItem.events[0] Text("\(que.description)") .font(.title3) } } .refreshable { // 调用实例的刷新方法,无需重新创建实例 accept.refresh() } } } }
关键说明
@StateObject是SwiftUI 2.0+引入的,专门用于管理视图自身创建的ObservableObject实例,其生命周期与视图绑定- 方案二更符合ObservableObject的设计逻辑,能避免重复创建实例带来的资源消耗和状态丢失问题
内容的提问来源于stack exchange,提问作者dslCoding
相关产品推荐
相关产品推荐

