如何修复 TextField 绑定 <String> 以在 SwiftUI 中显示和编辑
How to fix TextField Binding <String> to show and edit in SwiftUI
我想在 TextField
中显示文本并能够对其进行编辑。但是我在绑定它时遇到了问题。这是我的代码:
struct DataView: View {
@ObservedObject private var dataPresenter = DataPresenter()
var body: some View {
VStack {
TextField("Name", text: $dataPresenter.data?.name ?? "") // This is the error
}
.onAppear(perform: {
dataPresenter.getData()
})
}
}
class DataPresenter: ObservableObject {
@Injected private var getDataInteractor: GetDataInteractor
@Injected private var cancellables: Set<AnyCancellable>
@Published var data: GetDataResp?
func getData() {
getDataInteractor.execute()
.sink { error in
print("Error:", error)
} receiveValue: { response in
if response.errorCode == "00" {
print(response)
self.data = response
}
}
.store(in: &cancellables)
}
}
struct GetDataResp: Codable, Equatable {
var name : String?
var address : String?
var email : String?
enum CodingKeys: String, CodingKey {
case name = "name"
case address = "address"
case email = "email"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decodeIfPresent(String.self, forKey: .name)
address = try values.decodeIfPresent(String.self, forKey: .address)
email = try values.decodeIfPresent(String.self, forKey: .email)
}
}
当我不在 $dataPresenter.data.name ?? ""
中使用 ?
时,我总是会收到这样的错误:
然后,当我用 ?
修复它时,我会收到更多这样的错误:
我陷入了这个错误循环,使用 force unwrap
会使应用程序崩溃。我有比名称更多的变量,所以我不能只 self.name = response.name ?? ""
在响应中。我该如何解决这个问题?
如有任何建议,我们将不胜感激。
TextField
需要 Binding
,而不仅仅是 String
。因此,当您在 Binding
为 nil 的情况下提供 ""
时,您最终会得到非等效类型(Binding<String>
vs String
)。
要解决此问题,您可能需要创建一个自定义绑定来处理 data
为 nil
的情况。
这是一种可能的解决方案:
struct DataView: View {
@ObservedObject private var dataPresenter = DataPresenter()
var body: some View {
VStack {
Text(dataPresenter.data?.name ?? "Empty")
TextField("Name", text: dataPresenter.nonOptionalNameBinding())
}
}
}
struct GetDataResp {
var name : String
}
class DataPresenter: ObservableObject {
@Published var data: GetDataResp?
func nonOptionalNameBinding() -> Binding<String> {
.init {
return self.data?.name ?? ""
} set: { newValue in
if self.data == nil {
self.data = GetDataResp(name: newValue)
} else {
self.data?.name = newValue
}
}
}
}
您可能需要根据需要在 set:
部分以不同方式处理这种情况。而且,当然,我删除了 GetDataResp
,我假设它比我那里的更详细,但这应该让你开始。
根据评论更新:
struct GetDataResp: Codable, Equatable {
var name : String?
var address : String?
var email : String?
}
struct DataView: View {
@ObservedObject private var dataPresenter = DataPresenter()
var body: some View {
VStack {
Text(dataPresenter.data?.name ?? "Empty")
TextField("Name", text: dataPresenter.nonOptionalBinding(keyPath: \.name))
TextField("Address", text: dataPresenter.nonOptionalBinding(keyPath: \.address))
TextField("Email", text: dataPresenter.nonOptionalBinding(keyPath: \.email))
}
}
}
class DataPresenter: ObservableObject {
@Published var data: GetDataResp?
func nonOptionalBinding(keyPath: WritableKeyPath<GetDataResp,String?>) -> Binding<String> {
.init {
return self.data?[keyPath: keyPath] ?? ""
} set: { newValue in
if self.data == nil {
self.data = GetDataResp()
}
self.data?[keyPath: keyPath] = newValue
}
}
}
我想在 TextField
中显示文本并能够对其进行编辑。但是我在绑定它时遇到了问题。这是我的代码:
struct DataView: View {
@ObservedObject private var dataPresenter = DataPresenter()
var body: some View {
VStack {
TextField("Name", text: $dataPresenter.data?.name ?? "") // This is the error
}
.onAppear(perform: {
dataPresenter.getData()
})
}
}
class DataPresenter: ObservableObject {
@Injected private var getDataInteractor: GetDataInteractor
@Injected private var cancellables: Set<AnyCancellable>
@Published var data: GetDataResp?
func getData() {
getDataInteractor.execute()
.sink { error in
print("Error:", error)
} receiveValue: { response in
if response.errorCode == "00" {
print(response)
self.data = response
}
}
.store(in: &cancellables)
}
}
struct GetDataResp: Codable, Equatable {
var name : String?
var address : String?
var email : String?
enum CodingKeys: String, CodingKey {
case name = "name"
case address = "address"
case email = "email"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decodeIfPresent(String.self, forKey: .name)
address = try values.decodeIfPresent(String.self, forKey: .address)
email = try values.decodeIfPresent(String.self, forKey: .email)
}
}
当我不在 $dataPresenter.data.name ?? ""
中使用 ?
时,我总是会收到这样的错误:
然后,当我用 ?
修复它时,我会收到更多这样的错误:
我陷入了这个错误循环,使用 force unwrap
会使应用程序崩溃。我有比名称更多的变量,所以我不能只 self.name = response.name ?? ""
在响应中。我该如何解决这个问题?
如有任何建议,我们将不胜感激。
TextField
需要 Binding
,而不仅仅是 String
。因此,当您在 Binding
为 nil 的情况下提供 ""
时,您最终会得到非等效类型(Binding<String>
vs String
)。
要解决此问题,您可能需要创建一个自定义绑定来处理 data
为 nil
的情况。
这是一种可能的解决方案:
struct DataView: View {
@ObservedObject private var dataPresenter = DataPresenter()
var body: some View {
VStack {
Text(dataPresenter.data?.name ?? "Empty")
TextField("Name", text: dataPresenter.nonOptionalNameBinding())
}
}
}
struct GetDataResp {
var name : String
}
class DataPresenter: ObservableObject {
@Published var data: GetDataResp?
func nonOptionalNameBinding() -> Binding<String> {
.init {
return self.data?.name ?? ""
} set: { newValue in
if self.data == nil {
self.data = GetDataResp(name: newValue)
} else {
self.data?.name = newValue
}
}
}
}
您可能需要根据需要在 set:
部分以不同方式处理这种情况。而且,当然,我删除了 GetDataResp
,我假设它比我那里的更详细,但这应该让你开始。
根据评论更新:
struct GetDataResp: Codable, Equatable {
var name : String?
var address : String?
var email : String?
}
struct DataView: View {
@ObservedObject private var dataPresenter = DataPresenter()
var body: some View {
VStack {
Text(dataPresenter.data?.name ?? "Empty")
TextField("Name", text: dataPresenter.nonOptionalBinding(keyPath: \.name))
TextField("Address", text: dataPresenter.nonOptionalBinding(keyPath: \.address))
TextField("Email", text: dataPresenter.nonOptionalBinding(keyPath: \.email))
}
}
}
class DataPresenter: ObservableObject {
@Published var data: GetDataResp?
func nonOptionalBinding(keyPath: WritableKeyPath<GetDataResp,String?>) -> Binding<String> {
.init {
return self.data?[keyPath: keyPath] ?? ""
} set: { newValue in
if self.data == nil {
self.data = GetDataResp()
}
self.data?[keyPath: keyPath] = newValue
}
}
}