【问题标题】: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")
    }
  }
}

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

【问题讨论】:

    标签: ios swift swiftui combine


    【解决方案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 框架,所以我不想将其标记为正确答案。你明白吗?
      猜你喜欢
      • 1970-01-01
      • 2012-03-23
      • 2012-02-15
      • 2016-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-19
      相关资源
      最近更新 更多