12

我想@State为 UI 和计算值都使用一个变量。

例如,假设我有一个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

3 回答 3

13

您不能将 @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 {
    @StateObject var store = SearchStore()

    var body: some View {
        VStack {
            TextField("type something...", text: $store.query)
            Button("search") {
                self.store.fetch()
            }
        }
    }
}
于 2019-08-11T19:58:38.140 回答
1

您还可以使用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
于 2021-11-23T01:00:19.817 回答
-1

最新的测试版改变了变量的发布方式,所以我认为你甚至不想尝试。制作 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 使用的魔法,而不是使用变量。

于 2019-07-31T12:41:30.277 回答