组合框架的基本使用
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 框架,所以我不想将其标记为正确答案。你明白吗?以上是关于组合框架的基本使用的主要内容,如果未能解决你的问题,请参考以下文章