mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
184 lines
6.5 KiB
Swift
184 lines
6.5 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Only support 64bit
|
|
#if !(os(iOS) && (arch(i386) || arch(arm)))
|
|
|
|
@_exported import Foundation // Clang module
|
|
import Combine
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
extension NotificationCenter {
|
|
/// Returns a publisher that emits events when broadcasting notifications.
|
|
///
|
|
/// - Parameters:
|
|
/// - name: The name of the notification to publish.
|
|
/// - object: The object posting the named notfication. If `nil`, the publisher emits elements for any object producing a notification with the given name.
|
|
/// - Returns: A publisher that emits events when broadcasting notifications.
|
|
public func publisher(
|
|
for name: Notification.Name,
|
|
object: AnyObject? = nil
|
|
) -> NotificationCenter.Publisher {
|
|
return NotificationCenter.Publisher(center: self, name: name, object: object)
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
extension NotificationCenter {
|
|
/// A publisher that emits elements when broadcasting notifications.
|
|
public struct Publisher: Combine.Publisher {
|
|
public typealias Output = Notification
|
|
public typealias Failure = Never
|
|
|
|
/// The notification center this publisher uses as a source.
|
|
public let center: NotificationCenter
|
|
/// The name of notifications published by this publisher.
|
|
public let name: Notification.Name
|
|
/// The object posting the named notfication.
|
|
public let object: AnyObject?
|
|
|
|
/// Creates a publisher that emits events when broadcasting notifications.
|
|
///
|
|
/// - Parameters:
|
|
/// - center: The notification center to publish notifications for.
|
|
/// - name: The name of the notification to publish.
|
|
/// - object: The object posting the named notfication. If `nil`, the publisher emits elements for any object producing a notification with the given name.
|
|
public init(center: NotificationCenter, name: Notification.Name, object: AnyObject? = nil) {
|
|
self.center = center
|
|
self.name = name
|
|
self.object = object
|
|
}
|
|
|
|
public func receive<S: Subscriber>(subscriber: S) where S.Input == Output, S.Failure == Failure {
|
|
subscriber.receive(subscription: Notification.Subscription(center, name, object, subscriber))
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
extension NotificationCenter.Publisher: Equatable {
|
|
public static func == (
|
|
lhs: NotificationCenter.Publisher,
|
|
rhs: NotificationCenter.Publisher
|
|
) -> Bool {
|
|
return lhs.center === rhs.center
|
|
&& lhs.name == rhs.name
|
|
&& lhs.object === rhs.object
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
extension Notification {
|
|
fileprivate final class Subscription<S: Subscriber>: Combine.Subscription, CustomStringConvertible, CustomReflectable, CustomPlaygroundDisplayConvertible
|
|
where
|
|
S.Input == Notification
|
|
{
|
|
private let lock = Lock()
|
|
|
|
// This lock can only be held for the duration of downstream callouts
|
|
private let downstreamLock = RecursiveLock()
|
|
|
|
private var demand: Subscribers.Demand // GuardedBy(lock)
|
|
|
|
private var center: NotificationCenter? // GuardedBy(lock)
|
|
private let name: Notification.Name // Stored only for debug info
|
|
private var object: AnyObject? // Stored only for debug info
|
|
private var observation: AnyObject? // GuardedBy(lock)
|
|
|
|
var description: String { return "NotificationCenter Observer" }
|
|
var customMirror: Mirror {
|
|
lock.lock()
|
|
defer { lock.unlock() }
|
|
return Mirror(self, children: [
|
|
"center": center as Any,
|
|
"name": name as Any,
|
|
"object": object as Any,
|
|
"demand": demand
|
|
])
|
|
}
|
|
var playgroundDescription: Any { return description }
|
|
|
|
init(_ center: NotificationCenter,
|
|
_ name: Notification.Name,
|
|
_ object: AnyObject?,
|
|
_ next: S)
|
|
{
|
|
self.demand = .max(0)
|
|
self.center = center
|
|
self.name = name
|
|
self.object = object
|
|
|
|
self.observation = center.addObserver(
|
|
forName: name,
|
|
object: object,
|
|
queue: nil
|
|
) { [weak self] note in
|
|
guard let self = self else { return }
|
|
|
|
self.lock.lock()
|
|
guard self.observation != nil else {
|
|
self.lock.unlock()
|
|
return
|
|
}
|
|
|
|
let demand = self.demand
|
|
if demand > 0 {
|
|
self.demand -= 1
|
|
}
|
|
self.lock.unlock()
|
|
|
|
if demand > 0 {
|
|
self.downstreamLock.lock()
|
|
let additionalDemand = next.receive(note)
|
|
self.downstreamLock.unlock()
|
|
|
|
if additionalDemand > 0 {
|
|
self.lock.lock()
|
|
self.demand += additionalDemand
|
|
self.lock.unlock()
|
|
}
|
|
} else {
|
|
// Drop it on the floor
|
|
}
|
|
}
|
|
}
|
|
|
|
deinit {
|
|
lock.cleanupLock()
|
|
downstreamLock.cleanupLock()
|
|
}
|
|
|
|
func request(_ d: Subscribers.Demand) {
|
|
lock.lock()
|
|
demand += d
|
|
lock.unlock()
|
|
}
|
|
|
|
func cancel() {
|
|
lock.lock()
|
|
guard let center = self.center,
|
|
let observation = self.observation else {
|
|
lock.unlock()
|
|
return
|
|
}
|
|
self.center = nil
|
|
self.observation = nil
|
|
self.object = nil
|
|
lock.unlock()
|
|
|
|
center.removeObserver(observation)
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* !(os(iOS) && (arch(i386) || arch(arm))) */
|