【问题标题】:onReceive called infinitely in swiftUIonReceive 在 swiftUI 中无限调用
【发布时间】:2020-03-22 15:51:36
【问题描述】:

我得到一个无限循环,当使用带有@Published 变量的协议时,onReceive 被无限调用。要在协议中使用@Published 变量,我正在使用这个stackoverflow answer。 MyImageView 中的这一行:

if self.viewModel.answered {

似乎在

中引起了呼叫
onReceive { self.viewModel.objectWillChange

在 ContentView 内。

知道如何进行这项工作吗?

这是完整的代码:

环境对象:

import UIKit
import SwiftUI
import Combine
import Foundation

protocol MyProtocol: AnyObject {
    var answered: Bool { get set }
    var answeredPublished: Published<Bool> { get }
    var answeredPublisher: Published<Bool>.Publisher { get }
}

class GameViewModel: ObservableObject & MyProtocol {

    @Published var answered = false
    var answeredPublished: Published<Bool> { _answered }
    var answeredPublisher: Published<Bool>.Publisher { $answered }

}

观看次数:

import SwiftUI

struct MyImageView: View {
    @EnvironmentObject var viewModel: GameViewModel

    var body: some View {
        if self.viewModel.answered {
            print("not nil")
            return AnyView(Image("clearImage")
                .resizable()
                .scaledToFit()
            )
        }
        else {
            print("nil")
            return AnyView(
                Text(self.viewModel.answered ? "true" : "false")
            )
        }
    }
}

struct ViewBelow<ViewModel: ObservableObject & MyProtocol>: View {
    @EnvironmentObject var viewModel: ViewModel

    var body: some View {
        Text("below")
        .onReceive(self.viewModel.objectWillChange,

           perform: { _ in
               print("onReceive target")
           }
        )
    }
}


struct ContentView: View {
    @EnvironmentObject var viewModel: GameViewModel
    var body: some View {
        GeometryReader {
            geo in
            VStack {
                MyImageView()

                ViewBelow<GameViewModel>()
            }
        }
    }
}

场景委托 导入 UIKit 导入 SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = ContentView().environmentObject(GameViewModel())

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

【问题讨论】:

  • 不,不是。使用 Xcode 11.4 / iOS 13.4 测试 - 按预期工作。我刚刚将.onTapGesture 添加到MyImageView() 以测试answered 的变化。
  • MyProtocol 背后的理念是什么?我有点迷路了……
  • @user3441734 : 我已经更新了视图代码,现在协议背后的原因应该更清楚了。
  • @Asperi :我正在使用 XCode 11.3.1 和 iPhone 8 模拟器 (13.3),我得到了无限循环。你能用更新后的代码进行验证吗?

标签: swift swiftui


【解决方案1】:

这对我有用:

class MyPublishedProperties {
    @Published var answered = false
}

protocol MyProtocol: MyPublishedProperties {
    func changePublishedPropertyValue(newValue: Bool)
}


class GameViewModel: ObservableObject & MyPublishedProperties, MyProtocol {

    func changePublishedPropertyValue(newValue: Bool) {
        answered = newValue
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多