SwiftUI onReceive 不适用于 UIPasteboard 发布者
Posted
技术标签:
【中文标题】SwiftUI onReceive 不适用于 UIPasteboard 发布者【英文标题】:SwiftUI onReceive don't work with UIPasteboard publisher 【发布时间】:2021-05-07 16:12:28 【问题描述】:我想通过 onReceive 订阅 SwiftUI 中的 UIPasteboard 更改。
pHasStringsPublisher
不会在剪贴板中的某些内容发生更改时立即更新,我不明白为什么。
import SwiftUI
struct ContentView: View
let pasteboard = UIPasteboard.general
@State var pString: String = "pString"
@State var pHasStrings: Bool = false
@State var pHasStringsPublisher: Bool = false
var body: some View
VStack
Spacer()
Text("b: '\(self.pString)'")
.font(.headline)
Text("b: '\(self.pHasStrings.description)'")
.font(.headline)
Text("p: '\(self.pHasStringsPublisher.description)'")
.font(.headline)
Spacer()
Button(action:
self.pString = self.pasteboard.string ?? "nil"
self.pHasStrings = self.pasteboard.hasStrings
, label:
Text("read pb")
.font(.largeTitle)
)
Button(action:
self.pasteboard.items = []
, label:
Text("clear pb")
.font(.largeTitle)
)
Button(action:
self.pasteboard.string = Date().description
, label:
Text("set pb")
.font(.largeTitle)
)
.onReceive(self.pasteboard
.publisher(for: \.hasStrings)
.print()
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
, perform:
hasStrings in
print("pasteboard publisher")
self.pHasStringsPublisher = hasStrings
)
【问题讨论】:
您确定hasStrings
是符合 KVO 的属性吗? publisher(for: KeyPath
方法仅适用于符合 KVO 的属性,因为它在底层使用了 KVO。该属性的文档没有提到它符合 KVO,所以我怀疑它实际上不是。您需要找到另一种方法来观察粘贴板的变化。
感谢您的澄清。我不知道符合 KVO 的属性,但我会记住这一点。
【参考方案1】:
据我所知,UIPasteboard
的所有属性均未记录为支持键值观察 (KVO),因此 publisher(for: \.hasStrings)
可能永远不会发布任何内容。
相反,您可以从默认的NotificationCenter
监听UIPasteboard.changedNotification
。但是,如果您希望用户从另一个应用程序中复制字符串,那仍然不够,因为如果在您的应用程序处于后台时更改了其内容,则粘贴板不会发布 changedNotification
。所以你也需要收听UIApplication.didBecomeActiveNotification
。
让我们在UIPasteboard
的扩展中将其全部包装起来:
extension UIPasteboard
var hasStringsPublisher: AnyPublisher<Bool, Never>
return Just(hasStrings)
.merge(
with: NotificationCenter.default
.publisher(for: UIPasteboard.changedNotification, object: self)
.map _ in self.hasStrings )
.merge(
with: NotificationCenter.default
.publisher(for: UIApplication.didBecomeActiveNotification, object: nil)
.map _ in self.hasStrings )
.eraseToAnyPublisher()
并像这样使用它:
var body: some View
VStack
blah blah blah
.onReceive(UIPasteboard.general.hasStringsPublisher) hasStrings = $0
【讨论】:
以上是关于SwiftUI onReceive 不适用于 UIPasteboard 发布者的主要内容,如果未能解决你的问题,请参考以下文章
无法添加窗口 - 令牌 null 不适用于广播接收器的 OnReceive 内的应用程序
Swift UI 实时预览画布不适用于 macOS Catalina 和 Xcode 11.0