组合框架的基本使用

Posted

技术标签:

【中文标题】组合框架的基本使用【英文标题】:Basic use of the Combine Framework 【发布时间】:2021-01-27 16:11:18 【问题描述】:

Swift 5.2 ios 14

尝试理解 SwiftUI 中的组合框架,并使用我在网上找到的示例将这段代码放在一起。但是……这个例子并不完整。

现在,当我更改设备的方向时,它会写入方向,但是如何在我的主循环中使用它?我似乎也找不到任何要订阅的内容,所以我尝试只使用 onChange。遗憾的是,这不起作用。

class SizeClassViewV: ObservableObject 
  @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
  @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?

  enum Orientation 
    case portrait
    case landscape
  
  @Published var orientation: Orientation = .portrait
  private var listener: AnyCancellable?

  init() 
    if horizontalSizeClass == .compact && verticalSizeClass == .regular 
      orientation = .portrait
     else if horizontalSizeClass == .regular && verticalSizeClass == .compact 
      orientation = .landscape
    
    listener = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
        .compactMap  ($0.object as? UIDevice)?.orientation 
        .compactMap  deviceOrientation -> Orientation? in
            if deviceOrientation.isPortrait 
                return .portrait
             else if deviceOrientation.isLandscape 
                return .landscape
             else 
                return nil
            
        
        .assign(to: \.orientation, on: self)
  

  deinit 
    listener?.cancel()
  

在我的主循环中现在看起来像这样吗?

struct ContentView: View 
@State var orient = SizeClassViewX()
var body: some View 
  Text("foo")
    .onChange(of: orient.orientation)  ( _ ) in
      print("changed")
    
  

更改方向时从不打印更改?

【问题讨论】:

【参考方案1】:
final class SizeClassViewV: ObservableObject 
  enum Orientation: Equatable 
    case portrait
    case landscape
  

  @Published var orientation: Orientation = .portrait

  private var listener: AnyCancellable?

  init() 
    orientation = UIDevice.current.orientation.isPortrait ? Orientation.portrait : .landscape
    listener = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
      .compactMap  ($0.object as? UIDevice)?.orientation 
      .map  $0.isPortrait ? Orientation.portrait : .landscape 
      .assign(to: \.orientation, on: self)
  

  deinit 
    listener?.cancel()
  

struct ContentView: View 
  @ObservedObject var orient  = SizeClassViewV()

  var body: some View 
    Text("Hello, world!")
      .padding()
      .onReceive(orient.$orientation)  value in
        print(value)
      
  

【讨论】:

弗拉基米尔,谢谢,但你改变了什么?不,等等,我也看到了其他变化…… @user3069232 主要变化是: 1. 状态改变 -> ObservedObject 2. .onChange(of: orient.orientation) -> .onReceive(orient.$orientation)【参考方案2】:

我似乎找不到要订阅的内容

如果您查看onReceive 声明,您会发现它接受了一个组合Publisher

@inlinable public func onReceive<P>(_ publisher: P, perform action: @escaping (P.Output) -> Void) -> some View where P : Publisher, P.Failure == Never

这意味着如果你想订阅orientation改变组合的方式,你可以只使用onReceive并传递相关的Publisher

struct ContentView: View 
    @State var orient = SizeClassViewV()
    var body: some View 
        Text("foo")
            .onReceive(orient.$orientation)  _ in
                print("changed")
            
    

【讨论】:

【参考方案3】:

它实际上以不同的方式工作 - Environment 包装器用于 SwiftUI 视图的上下文,因此在以下演示中使用:

struct ContentView: View 
    @Environment(\.verticalSizeClass) var verticalSizeClass
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    
    var body: some View 
        Text("foo")
            .onChange(of: horizontalSizeClass)  _ in
                print("horizontal class changed")
            
            .onChange(of: verticalSizeClass)  _ in
                print("vertical class changed")
            
    

【讨论】:

感谢 Asperi。我将使用它,但目标是使用 Combine 框架,所以我不想将其标记为正确答案。你明白吗?

以上是关于组合框架的基本使用的主要内容,如果未能解决你的问题,请参考以下文章

组合地理定位框架

组合框架:如何在继续之前异步处理数组的每个元素

Koa基本使用

集合框架

IO组件之Commons 基本使用步骤

scss 使用&符号(&)与基本元素组合使用Sass