我认为此错误消息是 Xcode 12 中的 SwiftUI 的新消息,因为它在 Google 中的点击率为 0,而该消息本身相当通用:
在安装在 View 之外访问 State 的值。这将导致初始值的常量绑定并且不会更新。
我有以下代码(删除了一些绒毛):
public struct ContentView: View {
@ObservedObject var model: RootViewModel
public var body: some View {
VStack(alignment: .center, content: {
Picker(selection: model.$amount, label: Text("Amount")) {
Text("€1").tag(1)
Text("€2").tag(2)
Text("€5").tag(5)
Text("€10").tag(10)
}.pickerStyle(SegmentedPickerStyle())
Text("Donating: €\(model.amount)").font(.largeTitle)
}).padding(.all, 20.0)
}
}
public class RootViewModel: ObservableObject {
@State public var amount: Int = 1
}
Run Code Online (Sandbox Code Playgroud)
我曾经有field权利,ContentView而且工作正常。现在 UI 不再更新,而是我收到了运行时警告。
我一直在看通过SwiftUI WWDC进行的数据流。他们有一张带有示例代码的幻灯片,其中他们使用Timer发布者,该发布者连接到SwiftUI视图,并随时间更新UI。
我正在编写一些代码,在其中我想做完全相同的事情,但是无法弄清楚它PodcastPlayer.currentTimePublisher是如何实现的,然后将其连接到UI结构。我还看了所有关于Combine的视频。
我该如何实现?
示例代码:
struct PlayerView : View {
let episode: Episode
@State private var isPlaying: Bool = true
@State private var currentTime: TimeInterval = 0.0
var body: some View {
VStack { // ...
Text("\(playhead, formatter: currentTimeFormatter)")
}
.onReceive(PodcastPlayer.currentTimePublisher) { newCurrentTime in
self.currentTime = newCurrentTime
}
}
}
Run Code Online (Sandbox Code Playgroud) 我有一个核心数据模型,其中一个实体生成到 class 中Task。我正在尝试objectWillChange从NSManagedObject发送(自动,无需手动工作)中获取合并发布者,但它不会。任务实体有一个name属性。
let task = Task(context: container.viewContext)
let taskSubscription = task.objectWillChange.sink(receiveValue: { _ in
print("Task changed")
})
task.name = "Foo" // WILL NOT trigger
Run Code Online (Sandbox Code Playgroud)
如果我手动调用发送,订阅将起作用:
task.objectWillChange.send() // Will trigger
Run Code Online (Sandbox Code Playgroud)
如果我用一个 simple 替换ObservableObject它,它将按预期工作:
class DummyTask: ObservableObject {
@Published var name: String?
}
Run Code Online (Sandbox Code Playgroud)
let dummy = DummyTask()
let dummySubscription = dummy.objectWillChange.sink(receiveValue: { _ in
print("Dummy changed")
})
dummy.name = "Foo" // Will trigger
dummy.objectWillChange.send() // Will trigger
Run Code Online (Sandbox Code Playgroud)
NSManagedObject 被窃听了吗?我应该如何观察通用实体对象的变化?我应该如何让 SwiftUI 看到它们? …
我有一些使用 RxSwift 构建的代码,我正在尝试将其转换为使用 Apple 的 Combine 框架。
一种非常常见的模式是使用Observable.create一次性可观察对象(通常是网络请求)。像这样的东西:
func loadWidgets() -> Observable<[Widget]> {
return Observable.create { observer in
// start the request when someone subscribes
let loadTask = WidgetLoader.request("allWidgets", completion: { widgets in
// publish result on success
observer.onNext(widgets)
observer.onComplete()
}, error: { error in
// publish error on failure
observer.onError()
})
// allow cancellation
return Disposable {
loadTask.cancel()
}
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试将其映射到结合,但我一直无法弄清楚。我能得到的最接近的是使用 Future 来做这样的事情:
func loadWidgets() -> AnyPublisher<[Widget], Error> {
return Future<[Widget], Error> { resolve in
// …Run Code Online (Sandbox Code Playgroud) 有没有办法指定 count 应该只在主线程上发布?我看过一些讨论使用 设置发布者的文档receive(on:),但在这种情况下,@Publisher包装器隐藏了该逻辑。
import SwiftUI
import Combine
class MyCounter: ObservableObject {
@Published var count = 0
public static let shared = MyCounter()
private init() { }
}
struct ContentView: View {
@ObservedObject var state = MyCounter.shared
var body: some View {
return VStack {
Text("Current count: \(state.count)")
Button(action: increment) {
HStack(alignment: .center) {
Text("Increment")
.foregroundColor(Color.white)
.bold()
}
}
}
}
private func increment() {
NetworkUtils.count()
}
}
public class NetworkUtils {
public static …Run Code Online (Sandbox Code Playgroud) 当使用 Swift/Combine 中的 retry() 发生某些错误时,我想多次发出网络请求。发布者内部的块只被调用一次,这意味着当发生错误时,对真正的应用程序只有一个请求。我的代码是:
import UIKit
import Combine
import PlaygroundSupport
enum TestFailureCondition: Error {
case invalidServerResponse
}
var backgroundQueue: DispatchQueue = DispatchQueue(label: "backgroundQueue")
var failPublisher: AnyPublisher<(Data, URLResponse), Error> {
Future<(Data, URLResponse), Error> { promise in
print("Attempt to call")
backgroundQueue.asyncAfter(deadline: .now() + Double.random(in: 1..<3)) {
promise(.failure(TestFailureCondition.invalidServerResponse))
}
}
.eraseToAnyPublisher()
}
let cancellable = failPublisher
.print("(1)>")
.retry(3)
.print("(2)>")
.sink(receiveCompletion: { fini in
print(" ** .sink() received the completion:", String(describing: fini))
PlaygroundPage.current.finishExecution()
}, receiveValue: { stringValue in
print(" ** .sink() received \(stringValue)") …Run Code Online (Sandbox Code Playgroud) 我正在寻找在textfields和之间创建绑定的最佳方法ViewModel。目前我正在@State为每个文本字段创建一个,并在需要时手动将值从文本字段发送到 viewModel 属性。我很确定这不是最好的方法......有没有办法将TextField与ViewModel财产绑定?
这是我当前的代码:
struct SigninView: View {
@State var username:String = ""
@State var password:String = ""
var viewModel:SignInViewModel
var body: some View {
VStack(alignment: .leading, spacing: 15.0){
DefaultTextField(placeholder: "username", value: $username)
DefaultTextField(placeholder: "password", value: $password)
Spacer()
FillButton(title:"Sign In"){
///// IS THIS CORRECT?
self.viewModel.email = self.username
self.viewModel.password = self.password
//------------------
self.viewModel.signin()
}
}.padding()
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型类似于:
class SignInViewModel:ObservableObject{
var username:String? = nil
var password:String? = nil
Run Code Online (Sandbox Code Playgroud) 我正在尝试在合并框架和 SwiftUI 中测试一个简单的发布者。我的测试在我的视图模型中测试了一个名为 isValid 的已发布布尔值。我的视图模型还有一个已发布的用户名字符串,当该字符串发生更改并变为 3 个或更多字符时,isValid 会被分配该值。这是视图模型。我确信我不了解发布商如何在测试环境、时间安排等中工作......提前致谢。
public class UserViewModel: ObservableObject {
@Published var username = ""
@Published var isValid = false
private var disposables = Set<AnyCancellable>()
init() {
$username
.receive(on: RunLoop.main)
.removeDuplicates()
.map { input in
print("~~~> \(input.count >= 3)")
return input.count >= 3
}
.assign(to: \.isValid, on: self)
.store(in: &disposables)
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的观点,这里并不重要
struct ContentView: View {
@ObservedObject private var userViewModel = UserViewModel()
var body: some View {
TextField("Username", text: $userViewModel.username)
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的测试文件和失败的单个测试
class StackoverFlowQuestionTests: XCTestCase …Run Code Online (Sandbox Code Playgroud) 我正在使用 adataTaskPublisher来获取一些数据:
func downloadData(_ req: URLRequest) {
self.cancelToken = dataTaskPublisher(for: req).sink { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
如果在请求正在进行时调用该函数,我想返回。
目前我要么:
1.cancelToken在接收器中将设置为 nil 或
2. Crate 并管理一个isDownloading变量。
是否有内置的方法来检查是否dataTaskPublisher正在运行(以及可选的进度)?
我现在正在学习 Swift Combine,找到了非常简单的视频教程,但是由于某种原因,当我尝试在 PassthroughSubject<Int, WeatherError>() 中使用我的枚举时出现错误
检查此代码:
import Combine
enum WeatherError: Error {
case thingsJustHappen
}
let weatherPublisher = PassthroughSubject<Int, WeatherError>()
let subscriber = weatherPublisher
.filter {$0 > 10}
.sink { value in
print("\(value)")
}
weatherPublisher.send(10)
weatherPublisher.send(30)
Run Code Online (Sandbox Code Playgroud)
“.filter”突出显示,错误是:
Referencing instance method 'sink(receiveValue:)' on 'Publisher'
requires the types 'Publishers.Filter<PassthroughSubject<Int, WeatherError>>.Failure'
(aka 'WeatherError') and 'Never' be equivalent
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,这段代码在视频教程中有效。我怎样才能让我的 WeatherError 和 Never 相等???