[英]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?? ""
$dataPresenter.data.name?? ""
,我總是收到這樣的錯誤:
然后,當我用?
,我得到更多這樣的錯誤:
我陷入了這個錯誤循環,使用force unwrap
會使應用程序崩潰。 我有比名字更多的變量,所以我不能只是self.name = response.name?? ""
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
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.