SwiftUI中如何从子视图修改父视图Protocol的可变属性?
问题分析与解决方案
问题场景
编写的SwiftUI代码中,期望点击子视图AnotherView的Text时修改父视图MyView中协议属性showView的值,触发对应逻辑,但Xcode报错:
Cannot assign to property: 'self' is immutable
代码示例:
protocol MyProtocol { var showView: Bool { get set } } struct MyView: View, MyProtocol { var showView = false var body: some View { ZStack(){ AnotherView(myProtocol: self) if showView { // code } } } } struct AnotherView: View { var myProtocol: MyProtocol var body: some View { ZStack(){ Text("Text") .onTapGesture{ myProtocol.showView = true // xcode报错行 } } } }
注:AnotherView为多场景复用视图,必须使用协议,仅需修改当前父视图的showView值。
错误原因
MyView是Swift值类型(结构体),传递self给子视图时会生成值拷贝,子视图修改的只是拷贝后的实例属性,无法影响原父视图;同时协议默认采用值语义,对于值类型实现者,子视图拿到的协议实例是不可变的,因此无法直接修改属性。
解决方案
方案一:类协议+ObservableObject(推荐)
将协议限定为仅类可遵循,把状态托管到ObservableObject子类中,通过引用类型传递实现原实例属性修改:
import SwiftUI import Combine // 限定协议仅类可遵循 protocol MyProtocol: AnyObject { var showView: Bool { get set } } // 用ObservableObject管理状态,@Published自动触发视图更新 class MyViewModel: ObservableObject, MyProtocol { @Published var showView = false } struct MyView: View { // 用StateObject持有ViewModel实例 @StateObject private var viewModel = MyViewModel() var body: some View { ZStack(){ AnotherView(myProtocol: viewModel) if viewModel.showView { Text("执行showView逻辑") .foregroundColor(.red) } } } } struct AnotherView: View { // 用weak避免循环引用 weak var myProtocol: MyProtocol? var body: some View { Text("点击修改showView") .onTapGesture{ myProtocol?.showView = true } } }
方案二:协议绑定属性
在协议中定义Binding<Bool>类型属性,父视图传递状态的绑定给子视图,通过绑定修改原状态:
import SwiftUI protocol MyProtocol { var showViewBinding: Binding<Bool> { get } } struct MyView: View, MyProtocol { @State private var showView = false // 实现协议要求的绑定属性 var showViewBinding: Binding<Bool> { $showView } var body: some View { ZStack(){ AnotherView(myProtocol: self) if showView { Text("执行showView逻辑") .foregroundColor(.red) } } } } struct AnotherView: View { var myProtocol: MyProtocol var body: some View { Text("点击修改showView") .onTapGesture{ myProtocol.showViewBinding.wrappedValue = true } } }
内容的提问来源于stack exchange,提问作者KANAYO AUGUSTIN UG
相关产品推荐
相关产品推荐

