SwiftUI onReceive 不适用于 UIPasteboard 发布者
SwiftUI onReceive don't work with UIPasteboard publisher
我想使用 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
})
}
}
据我所知,UIPasteboard
的 none 属性被记录为支持键值观察 (KVO),因此 publisher(for: \.hasStrings)
可能永远不会发布任何内容。
相反,您可以从默认 NotificationCenter
监听 UIPasteboard.changedNotification
。但是,如果您希望用户从另一个应用程序复制字符串,这仍然不够,因为如果粘贴板的内容在您的应用程序处于后台时发生更改,则粘贴板不会 post 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 = [=11=] }
}
我想使用 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
})
}
}
据我所知,UIPasteboard
的 none 属性被记录为支持键值观察 (KVO),因此 publisher(for: \.hasStrings)
可能永远不会发布任何内容。
相反,您可以从默认 NotificationCenter
监听 UIPasteboard.changedNotification
。但是,如果您希望用户从另一个应用程序复制字符串,这仍然不够,因为如果粘贴板的内容在您的应用程序处于后台时发生更改,则粘贴板不会 post 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 = [=11=] }
}