如何输入擦除`NotificationCenter.Notifications`?

问题描述 投票:0回答:1

我想创建一个异步序列,每当我收到一组通知的通知时就会发出该序列(Xcode 16.1 RC)。我的想法是,最简单的方法是使用 Apple 的

merge()
包中的
swift-async-algorithms
方法。我最初的天真的尝试:

    let note1 = NotificationCenter.default.notifications(named: .noteOne) 
    let note2 = NotificationCenter.default.notifications(named: .noteTwo)

    let merged = merge(note1, note2) // ❗️ Conformance of 'Notification' to 'Sendable' is unavailable

这个错误是有道理的;我知道

Notification
不可能是
Sendable
,因为它具有
userInfo
属性。所以我想我可以使用

将其映射到其他东西
    let note1 = NotificationCenter.default.notifications(named: .noteOne) 
      .map { _ in () }
    let note2 = NotificationCenter.default.notifications(named: .noteTwo)
      .map { _ in () }

    let merged = merge(note1, note2) // ❗️ Conformance of 'Notification' to 'Sendable' is unavailable

这行不通;我得到同样的编译错误。那么...我该怎么做?

swift swift-concurrency
1个回答
0
投票

添加

.map { _ in () }
不起作用,因为
AsyncMapSequence<Base, Transformed>
仅在满足所有这些条件时才符合
Sendable

  • Base
    Sendable
  • Base.Element
    Sendable
  • Transformed
    Sendable

另请参阅源代码

在这种情况下,第二个条件不满足。

Notification
不符合
Sendable

从源代码来看,这个

Sendable
一致性实际上是
@unchecked
。这是因为
AsyncMapSequence
被设计为采用非
Sendable
闭包(它将其存储在存储属性中),并且编译器无法判断这是安全的。

事实上,如果闭包是一个

@Sendable
闭包,那么只需要第一个条件。由于您的闭包仅映射到
()
,因此它 is
Sendable
,因此您可以编写自己的
AsyncMapSequence
来代替
@Sendable
闭包。

既然你的闭包也不是

async
,我写这个
SyncMapSequence
是为了让事情变得简单,

public struct SyncMapSequence<Base, Transformed>: AsyncSequence where Base: AsyncSequence {
    let f: @Sendable (Base.Element) -> Transformed
    let base: Base
    
    public struct AsyncIterator: AsyncIteratorProtocol {
        var baseIterator: Base.AsyncIterator
        let f: @Sendable (Base.Element) -> Transformed
        
        public mutating func next() async throws -> Transformed? {
            try await baseIterator.next().map(f)
        }
        
    }
    
    public func makeAsyncIterator() -> AsyncIterator {
        AsyncIterator(baseIterator: base.makeAsyncIterator(), f: f)
    }
}

extension SyncMapSequence: Sendable where Base: Sendable {}

extension AsyncSequence {
    func syncMap<Transformed>(transform: @Sendable @escaping (Element) -> Transformed) -> SyncMapSequence<Self, Transformed> {
        SyncMapSequence(f: transform, base: self)
    }
}

用途:

let note1 = NotificationCenter.default.notifications(named: .noteOne)
    .syncMap { _ in () }
let note2 = NotificationCenter.default.notifications(named: .noteTwo)
    .syncMap { _ in () }

let merged = merge(note1, note2)
© www.soinside.com 2019 - 2024. All rights reserved.