Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在SwiftUI中组合异步返回值_Swiftui_Combine - Fatal编程技术网

在SwiftUI中组合异步返回值

在SwiftUI中组合异步返回值,swiftui,combine,Swiftui,Combine,我有两个来自两个不同类的异步返回值,一个来自HealthKit,另一个来自MotionManager。我的目标是组合这些值并在swiftui视图中输出它们,在该视图中它每秒刷新一次。我知道我必须在这里查看联合收割机框架,但我不知道从哪里开始。我找不到很多描述Swiftui+Combine的教程。我知道我必须查看.CombineTest,但我必须编写自己的发布者和订阅者,还是可以使用我这里的@Published property包装器(@Published var motionData=motio

我有两个来自两个不同类的异步返回值,一个来自HealthKit,另一个来自MotionManager。我的目标是组合这些值并在swiftui视图中输出它们,在该视图中它每秒刷新一次。我知道我必须在这里查看联合收割机框架,但我不知道从哪里开始。我找不到很多描述Swiftui+Combine的教程。我知道我必须查看.CombineTest,但我必须编写自己的发布者和订阅者,还是可以使用我这里的@Published property包装器(@Published var motionData=motionData()和@Published var heartRateValue:Double=0.0)

我的MotionManager类:

我的HealthKitManager课程:

我开始创建一个combinedViewModel,但我被困在这里,不知道这是否是一种方法:

class CombinedViewModel: ObservableObject {

    @Published var motionManager: MotionManager = MotionManager()
    @Published var healthManager: HealthKitManager = HealthKitManager()

    var anyCancellable: AnyCancellable?

    init() {
        anyCancellable = Publishers
            .CombineLatest(motionManager.$motionValues,healthManager.$heartRateValue)
            .sink(receiveValue: {
                // Do something
            }
        })
    }
}
我需要关注什么?我是否需要完全学习combine框架来编写我自己的发布者和订阅者,或者@Published有什么东西可以完成这项工作?或者我需要使用我的CombinedViewModel使用另一种方法吗

添加了contentView以供参考:

struct ContentView: View {

    @State var isActive: Bool = false

    private var motion = MotionManager()
    private var health = HealthKitManager()

    @ObservedObject var combinedViewModel = CombinedViewModel(managerOne: motion, managerTwo: health)

    private var motionValues: MotionValues {
        return combinedViewModel.combinedValues.0
    }

    private var heartRateValue: Double {
        return combinedViewModel.combinedValues.1
    }


    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                Indicator(title: "X:", value: motionValues.rotationX)
                Indicator(title: "Y:", value: motionValues.rotationY)
                Indicator(title: "Z:", value: motionValues.rotationZ)
                Divider()
                Indicator(title: "Pitch:", value: motionValues.pitch)
                Indicator(title: "Roll:", value: motionValues.roll)
                Indicator(title: "Yaw:", value: motionValues.yaw)
                Divider()
                Indicator(title: "HR:", value: heartRateValue)
            }
            .padding(.horizontal, 10)
            Button(action: {
                self.isActive.toggle()
                self.isActive ? self.start() : self.stop()
            }) {
                Text(isActive ? "Stop" : "Start")
            }
            .background(isActive ? Color.green : Color.blue)
            .cornerRadius(10)
            .padding(.horizontal, 5)
        }.onAppear {
            self.health.autorizeHealthKit()
        }
    }

    private func start() {
        self.motion.startMotionUpdates()
        self.health.fetchHeartRateData(quantityTypeIdentifier: .heartRate)
    }

    private func stop() {
        self.motion.stopMotionUpdates()
        self.health.stopFetchingHeartRateData()
    }

}

您可以在您的
CombinedViewModel
中创建一个新的发布者(我建议使用
AnyPublisher
),该发布者将两者的输出结合起来。这是您的代码的简化版本,带有
组合视图模型

class ManagerOne {
  @Published var someValue = "Some Value"
}

class ManagerTwo {
  @Published var otherValue = "Other Value"
}

class CombinedViewModel {
  var combinedPublisher: AnyPublisher<(String, String), Never>

  init(managerOne: ManagerOne, managerTwo: ManagerTwo) {
    combinedPublisher = managerOne.$someValue
      .combineLatest(managerTwo.$otherValue)
      .eraseToAnyPublisher()
  }
}
关于这一点的旁注:

@Published var motionManager: MotionManager = MotionManager()
@Published var healthManager: HealthKitManager = HealthKitManager()

由于这两个管理器都是类,
$motionManager
$healthManager
仅在您将
motionManager
HealthKitManager
的新实例分配给它们时才会发出值。当任何一位经理的财产发生变化时都不会。我建议阅读这篇文章,这篇文章很好地解释了你需要什么:我不知道期货如何解决将两个
@Published
财产的输出组合成一个新的
@Published
财产的问题,我将阅读它并尝试学习一些东西:)你知道如何在我的contentView中实现这一点吗?我在我的原始帖子中添加了contentView,因为
combinedViewModel
是一个
@ObservedObject
视图应该在每次
combinedValue
更改时重新渲染。可以在视图模型上访问该属性,并根据需要获取值。或者你可以订阅组合视图模型。$combinedValue我直接尝试了这个,但没有成功:private var motion=MotionManager()private var health=HealthKitManager()@observeedobject var combinedViewModel=combinedViewModel(managerOne:motion,managertw:health)是的,我会打开一个新的。您的代码对于我所问的部分似乎还可以:)Tyit现在可以工作了,但是希望有人检查我的代码。
class ManagerOne {
  @Published var someValue = "Some Value"
}

class ManagerTwo {
  @Published var otherValue = "Other Value"
}

class CombinedViewModel {
  var combinedPublisher: AnyPublisher<(String, String), Never>

  init(managerOne: ManagerOne, managerTwo: ManagerTwo) {
    combinedPublisher = managerOne.$someValue
      .combineLatest(managerTwo.$otherValue)
      .eraseToAnyPublisher()
  }
}
class CombinedViewModel: ObservableObject {
  @Published var combinedValue: (String, String) = ("", "")

  var cancellables = Set<AnyCancellable>()

  init(managerOne: ManagerOne, managerTwo: ManagerTwo) {
    managerOne.$someValue
      .combineLatest(managerTwo.$otherValue)
      .sink(receiveValue: { [weak self] combined  in
        self?.combinedValue = combined
      })
      .store(in: &cancellables)
  }
}
@Published var motionManager: MotionManager = MotionManager()
@Published var healthManager: HealthKitManager = HealthKitManager()