Преобразование @State в издателя
Я хочу использовать @State
переменная как для пользовательского интерфейса, так и для вычисления значения.
Например, допустим, у меня есть TextField
связан с @State var userInputURL: String = "https://"
, Как бы я взял это userInputURL
и подключить его к издателю, чтобы я мог map
это в URL
,
Псевдокод:
$userInputURL.publisher()
.compactMap({ URL(string: $0) })
.flatMap({ URLSession(configuration: .ephemeral).dataTaskPublisher(for: $0).assertNoFailure() })
.eraseToAnyPublisher()
4 ответа
Вы не можете конвертировать @state в издателя, но вместо этого вы можете использовать ObservableObject.
import SwiftUI
final class SearchStore: ObservableObject {
@Published var query: String = ""
func fetch() {
$query
.map { URL(string: $0) }
.flatMap { URLSession.shared.dataTaskPublisher(for: $0) }
.sink { print($0) }
}
}
struct ContentView: View {
@ObservedObject var store = SearchStore()
var body: some View {
VStack {
TextField("type something...", text: $store.query)
Button("search") {
self.store.fetch()
}
}
}
}
Вы также можете использовать
onChange(of:)
чтобы ответить на
@State
изменения.
struct MyView: View {
@State var userInputURL: String = "https://"
var body: some View {
VStack {
TextField("search here", text: $userInputURL)
}
.onChange(of: userInputURL) { _ in
self.fetch()
}
}
func fetch() {
print("changed", userInputURL)
// ...
}
}
Выход:
changed https://t
changed https://ts
changed https://tsr
changed https://tsrs
changed https://tsrst
Последняя бета-версия изменила способ публикации переменных, поэтому я не думаю, что вы даже хотите попробовать. Создание классов ObservableObject довольно легко, но затем вы хотите добавить издателя для собственного использования:
class ObservableString: Combine.ObservableObject, Identifiable {
let id = UUID()
let objectWillChange = ObservableObjectPublisher()
let publisher = PassthroughSubject<String, Never>()
var string: String {
willSet { objectWillChange.send() }
didSet { publisher.send(string) }
}
init(_ string: String = "") { self.string = string }
}
Вместо @State
переменные, которые вы используете @ObservableObject
и не забывайте обращаться к строке свойств напрямую, а не использовать магию, которую использует @State.
После iOS 14.0 вы можете получить доступ к Publisher.
struct MyView: View {
@State var text: String?
var body: some View {
Text(text ?? "")
.onReceive($text.wrappedValue.publisher) { _ in
let publisher1: Optional<String>.Publisher = $text.wrappedValue.publisher
// ... or
let publisher2: Optional<String>.Publisher = _text.wrappedValue.publisher
}
}
}