如何创建绑定与显示类型不同的自定义SwiftUI Binding?
自定义SwiftUI Binding:解决类型转换与作用域问题
你需要绑定Date和Int类型数据,但以字符串形式显示,现有代码出现两个核心错误:
- 逃逸闭包捕获可变
self参数 - 找不到
$descriptiveDate/$descriptiveInt作用域
问题代码回顾
import SwiftUI struct BindingButton: View { @Binding var title: String var onTap: () -> Void var body: some View { Button { onTap() } label: { Text(title) } } } struct CustomBinding: View { @State var date: Date @State var int: Int lazy var descriptiveDate = Binding( get: { //Escaping closure captures mutating 'self' parameter return self.date.description }, set: { _ in } ) lazy var descriptiveInt = Binding( get: { //Escaping closure captures mutating 'self' parameter return String(self.int) }, set: { _ in } ) var body: some View { VStack { // Cannot find '$descriptiveDate' in scope BindingButton(title: $descriptiveDate) { date = Date() } // Cannot find '$descriptiveInt' in scope BindingButton(title: $descriptiveInt) { int += 2 } } } }
优雅解决方案(无需双重绑定)
方案1:在View body中直接创建Binding
把Binding的创建逻辑移到body内部,直接访问@State属性,既避免self捕获问题,也不需要使用$投影符号(因为我们直接生成了Binding<String>实例):
struct CustomBinding: View { @State var date: Date = Date() @State var int: Int = 0 var body: some View { VStack { BindingButton(title: Binding( get: { date.description }, set: { _ in } )) { date = Date() } BindingButton(title: Binding( get: { String(int) }, set: { _ in } )) { int += 2 } } } }
方案2:封装为计算属性
将自定义Binding封装成计算属性,替代lazy存储属性。计算属性不会修改self,因此不会触发逃逸闭包捕获可变参数的错误,同时直接返回Binding<String>实例,无需投影符号:
struct CustomBinding: View { @State var date: Date = Date() @State var int: Int = 0 // 可优化:添加自定义日期格式化 private static let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .short return formatter }() var descriptiveDate: Binding<String> { Binding( get: { Self.dateFormatter.string(from: date) }, set: { _ in } ) } var descriptiveInt: Binding<String> { Binding( get: { String(int) }, set: { _ in } ) } var body: some View { VStack { BindingButton(title: descriptiveDate) { date = Date() } BindingButton(title: descriptiveInt) { int += 2 } } } }
关键说明
$符号仅用于@State/@Binding等属性的投影,直接创建的Binding实例无需使用$- 计算属性或body内创建Binding时,Swift 5.3+可自动省略
self,避免捕获可变self的问题 - 若需更友好的日期显示,推荐使用自定义
DateFormatter而非默认的description
内容的提问来源于stack exchange,提问作者kunass2
相关产品推荐
相关产品推荐

