Swift 合并:从通知中心addObserver和选择器转到通知发布者
我已经看到了如何使用某个Swift 合并:从通知中心addObserver和选择器转到通知发布者,swift,combine,Swift,Combine,我已经看到了如何使用某个通知中心的发布者将其转换为组合,但还没有看到如何为以下内容进行转换: NotificationCenter.default.addObserver( self, selector: #selector(notCombine), name: NSNotification.Name(rawValue: "notCombine"), object: nil ) 我已经看到这是作为一个发布者
通知中心的发布者将其转换为组合,但还没有看到如何为以下内容进行转换:
NotificationCenter.default.addObserver(
self,
selector: #selector(notCombine),
name: NSNotification.Name(rawValue: "notCombine"),
object: nil
)
我已经看到这是作为一个发布者提供的,但是我没有一个选择器,也不知道该怎么做:
NotificationCenter.default.publisher(
for: Notification.Name(rawValue: "notCombine")
)
有人知道吗?谢谢 用例并不完全清楚,但这里有一个示例:
import Combine
import Foundation
class CombineNotificationSender {
var message : String
init(_ messageToSend: String) {
message = messageToSend
}
static let combineNotification = Notification.Name("CombineNotification")
}
class CombineNotificationReceiver {
var cancelSet: Set<AnyCancellable> = []
init() {
NotificationCenter.default.publisher(for: CombineNotificationSender.combineNotification)
.compactMap{$0.object as? CombineNotificationSender}
.map{$0.message}
.sink() {
[weak self] message in
self?.handleNotification(message)
}
.store(in: &cancelSet)
}
func handleNotification(_ message: String) {
print(message)
}
}
let receiver = CombineNotificationReceiver()
let sender = CombineNotificationSender("Message from sender")
NotificationCenter.default.post(name: CombineNotificationSender.combineNotification, object: sender)
sender.message = "Another message from sender"
NotificationCenter.default.post(name: CombineNotificationSender.combineNotification, object: sender)
导入联合收割机
进口基金会
类组合化发送器{
var消息:字符串
init(uMessageToSend:String){
message=messageToSend
}
静态let combineNotification=Notification.Name(“combineNotification”)
}
类组合化接收机{
var cancelSet:Set=[]
init(){
NotificationCenter.default.publisher(用于:CombineNotificationSender.combineNotification)
.compactMap{$0.object as?CombineNotificationSender}
.map{$0.message}
.sink(){
[弱自我]信息输入
自我?手动通知(信息)
}
.store(在:&cancelSet中)
}
func handleNotification(umessage:String){
打印(信息)
}
}
let receiver=CombineNotificationReceiver()
let sender=CombineNotificationSender(“来自发件人的消息”)
NotificationCenter.default.post(名称:CombineNotificationSender.combineNotification,对象:sender)
sender.message=“来自发件人的另一封邮件”
NotificationCenter.default.post(名称:CombineNotificationSender.combineNotification,对象:sender)
对于某些用例,您还可以使其成为仅合并的解决方案,而不使用通知
import Combine
import Foundation
class CombineMessageSender {
@Published var message : String?
}
class CombineMessageReceiver {
private var cancelSet: Set<AnyCancellable> = []
init(_ publisher: AnyPublisher<String?, Never>) {
publisher
.compactMap{$0}
.sink() {
self.handleNotification($0)
}
.store(in: &cancelSet)
}
func handleNotification(_ message: String) {
print(message)
}
}
let sender = CombineMessageSender()
let receiver = CombineMessageReceiver(sender.$message.eraseToAnyPublisher())
sender.message = "Message from sender"
sender.message = "Another message from sender"
导入联合收割机
进口基金会
类组合消息发送程序{
@已发布的var消息:字符串?
}
类组合消息接收器{
私有变量cancelSet:Set=[]
init(upublisher:AnyPublisher){
出版商
.compactMap{$0}
.sink(){
自我手动通知($0)
}
.store(在:&cancelSet中)
}
func handleNotification(umessage:String){
打印(信息)
}
}
let sender=CombineMessageSender()
let receiver=CombineMessageReceiver(发送方$message.橡皮擦到任何发布方())
sender.message=“来自发件人的邮件”
sender.message=“来自发件人的另一封邮件”
你说“我没有选择器”是对的,因为这是问题的一半。您可以使用Combine从通知中心接收通知,而无需使用选择器
这一点的另一半是,您可以将处理通知的逻辑向上推到合并管道中,这样,如果通知到达您手中,正确的结果就会从管道末端弹出
老式的方式
假设我有一个卡片视图,当通过发布通知点击它时,它会发出一声虚拟尖叫:
static let tapped = Notification.Name("tapped")
@objc func tapped() {
NotificationCenter.default.post(name: Self.tapped, object: self)
}
现在让我们假设,在本例中,当游戏收到其中一个通知时,它感兴趣的是发布通知的卡的name
属性的字符串值。如果我们用老式的方法来做,那么获取信息是一个两阶段的过程。首先,我们必须注册才能接收通知:
NotificationCenter.default.addObserver(self,
selector: #selector(cardTapped), name: Card.tapped, object: nil)
然后,当我们收到通知时,我们必须查看其对象
是否确实是一张卡,如果是,则获取其名称
属性并对其进行处理:
@objc func cardTapped(_ n:Notification) {
if let card = n.object as? Card {
let name = card.name
print(name) // or something
}
}
联合收割机
现在让我们使用Combine框架做同样的事情。我们通过调用其publisher
方法从通知中心获取发布者。但我们不会就此止步。如果对象
不是卡,我们不希望收到通知,因此我们使用compactMap
操作符将其安全地投射到卡上(如果它不是卡,管道将停止,就像什么都没有发生一样)。我们只需要卡的名称
,因此我们使用映射
操作符来获取它。结果如下:
let cardTappedCardNamePublisher =
NotificationCenter.default.publisher(for: Card.tapped)
.compactMap {$0.object as? Card}
.map {$0.name}
假设cardTappedCardNamePublisher
是视图控制器的实例属性。那么我们现在拥有的是一个实例属性,如果一张卡发布了点击的
通知,它将发布一个字符串,否则什么也不做
你明白我说的逻辑被推上管道是什么意思吗
那么,我们将如何安排接收从管道末端输出的内容呢?我们可以用水槽:
let sink = self.cardTappedCardNamePublisher.sink {
print($0) // the string name of a card
}
如果你尝试一下,你会发现我们现在有一种情况,每次用户点击一张卡片,卡片的名称就会被打印出来。这是我们早期的register-an-observer-with-a-selector方法的等效组合。谢谢,我将尝试实现这一点!我还将尝试在此Q中添加另一个悬赏,以向您提供悬赏,当另一个Viewcontroller中的publisher和订阅者位于另一个Viewcontroller中时,如何使用此悬赏?就像我们对通知中心所做的那样?你能告诉我如何在Comine中处理这种情况吗->我有一个包含内容视图的VC(比如主VC),其中不时包含另一个VC的内容视图,当用户使用combine在内容视图中点击VC上的按钮时,主VC如何得到通知?本讨论与我的这个问题和答案无关。请把你的问题当作真正的问题来问。