修改关联枚举的entry值报错:无法赋值给不可变String表达式
问题原因分析
你遇到的错误“Cannot assign to immutable expression of type 'String'”本质上有两个核心原因:
- 元组是值类型:
TextFieldInfo是一个元组,当你访问TextFieldModelEnum的info计算属性时,返回的是元组的副本,而不是指向原枚举关联值的引用——你修改这个副本的entry值,既不会影响原枚举实例,编译器也会因为临时值不可变而报错。 - 枚举关联值默认不可变:Swift枚举的关联值是通过
let绑定的,你无法直接修改枚举case里的关联值内容,必须重新创建枚举实例来覆盖原有的值。
解决方案
下面提供两种可行的修复方案,你可以根据自己的业务需求选择:
方案一:给枚举添加可变方法更新entry
我们可以给TextFieldModelEnum添加一个mutating方法,通过重新创建枚举实例来更新entry值:
public enum TextFieldModelEnum { case generic(type: TextFieldType, title: String) case entry(type: TextFieldType, title: String, entry: String) var info: TextFieldInfo { switch self { case .generic(let type, let title): return (type, title, "") case .entry(let type, let title, let entry): return (type, title, entry) } } // 添加mutating方法,用于更新entry值 mutating func updateEntry(_ newEntry: String) { switch self { case .generic(let type, let title): // 如果是generic类型,可选择转换为entry类型(根据你的业务逻辑调整) self = .entry(type: type, title: title, entry: newEntry) case .entry(let type, let title, _): // 重新创建entry case,替换原有entry值 self = .entry(type: type, title: title, entry: newEntry) } } }
然后在你的代理方法中调用这个方法即可:
extension ThirdViewController: TextProtocol { func getText(text: String) { // 调用updateEntry修改entry值 self.array[self.rowListSelected].updateEntry(text) let indexPaths = [IndexPath(row: self.rowListSelected, section: 0)] self.tableView.reloadRows(at: indexPaths, with: .none) print(text) } }
方案二:将枚举改为结构体(更推荐的方案)
如果你的TextFieldModelEnum的两个case本质上是同一类模型的不同状态,使用结构体会更灵活,因为结构体的属性可以直接声明为可变:
public struct TextFieldModel { let type: TextFieldType let title: String var entry: String // 用var声明,允许直接修改 // 对应原枚举的generic case init(type: TextFieldType, title: String) { self.type = type self.title = title self.entry = "" } // 对应原枚举的entry case init(type: TextFieldType, title: String, entry: String) { self.type = type self.title = title self.entry = entry } // 保留原有的info属性(如果需要兼容旧代码) var info: TextFieldInfo { return (type, title, entry) } }
此时你的代理方法可以直接修改entry属性:
extension ThirdViewController: TextProtocol { func getText(text: String) { self.array[self.rowListSelected].entry = text let indexPaths = [IndexPath(row: self.rowListSelected, section: 0)] self.tableView.reloadRows(at: indexPaths, with: .none) print(text) } }
内容的提问来源于stack exchange,提问作者bruno
相关产品推荐
相关产品推荐

