简体   繁体   中英

Basic use of the Combine Framework

Swift 5.2 iOS 14

Trying to understand the Combine Framework in SwiftUI and put this code together using an example I found on the web. But... the example wasn't complete.

Now when I change the orientation of my device, it does write to orientation, but how do I use this in my main loop? I cannot seem to find anything to subscribe too so I tried just using a onChange. Sadly that doesn't work.

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()
  }
}

In my main loop looks like this right now?

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

Changed is never printed when I change the orientation?

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)
      }
  }
}

I cannot seem to find anything to subscribe

If you take a look at the onReceive declaration, you can see that it accepts a Combine Publisher :

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

Which means that if you want to subscribe to the orientation changes the Combine way, you can just use onReceive and pass the relevant Publisher :

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

It works actually in different way - Environment wrapper is for context of SwiftUI view, so use as in following demo:

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")
            }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM