Skip to content

Commit 07b683e

Browse files
committed
implemented SCFNotificationCenter
1 parent 15052aa commit 07b683e

File tree

9 files changed

+373
-28
lines changed

9 files changed

+373
-28
lines changed

Package.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
// swift-tools-version: 5.7
2-
// The swift-tools-version declares the minimum version of Swift required to build this package.
32

43
import PackageDescription
54

65
let package = Package(
76
name: "SCFNotification",
87
products: [
9-
// Products define the executables and libraries a package produces, and make them visible to other packages.
108
.library(
119
name: "SCFNotification",
12-
targets: ["SCFNotification"]),
13-
],
14-
dependencies: [
15-
// Dependencies declare other packages that this package depends on.
16-
// .package(url: /* package url */, from: "1.0.0"),
10+
targets: ["SCFNotification"]
11+
),
1712
],
13+
dependencies: [],
1814
targets: [
19-
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
20-
// Targets can depend on other targets in this package, and on products in packages this package depends on.
2115
.target(
2216
name: "SCFNotification",
23-
dependencies: []),
17+
dependencies: []
18+
),
2419
.testTarget(
2520
name: "SCFNotificationTests",
26-
dependencies: ["SCFNotification"]),
21+
dependencies: ["SCFNotification"]
22+
),
2723
]
2824
)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// Array+.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/01/21.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
extension Array where Element == Observation {
12+
func filterWith(observer: UnsafeMutableRawPointer?, object: UnsafeRawPointer?) -> Array<Element> {
13+
filter {
14+
guard $0.observerPtr == observer,
15+
$0.objectPtr == object else {
16+
return false
17+
}
18+
return true
19+
}
20+
}
21+
22+
23+
func filterWith(observer: UnsafeMutableRawPointer?) -> Array<Element> {
24+
filter {
25+
guard $0.observerPtr == observer else {
26+
return false
27+
}
28+
return true
29+
}
30+
}
31+
32+
func remove(observer: UnsafeMutableRawPointer?, object: UnsafeRawPointer?) -> Array<Element> {
33+
filter {
34+
guard $0.observerPtr == observer,
35+
$0.objectPtr == object else {
36+
return true
37+
}
38+
return false
39+
}
40+
}
41+
42+
func removeEvery(observer: UnsafeMutableRawPointer?) -> Array<Element> {
43+
filter {
44+
guard $0.observerPtr == observer else {
45+
return true
46+
}
47+
return false
48+
}
49+
}
50+
51+
func cleanUpped() -> Array<Element> {
52+
filter {
53+
$0.observer != nil
54+
}
55+
}
56+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// CFNotificationCenter+.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/01/21.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
extension CFNotificationCenter {
12+
public static var local: CFNotificationCenter {
13+
CFNotificationCenterGetLocalCenter()
14+
}
15+
16+
public static var darwinNotify: CFNotificationCenter {
17+
CFNotificationCenterGetDarwinNotifyCenter()
18+
}
19+
20+
#if os(macOS)
21+
public static var distributed: CFNotificationCenter {
22+
CFNotificationCenterGetDistributedCenter()
23+
}
24+
#endif
25+
}
26+
27+
extension CFNotificationCenter {
28+
var centerType: SCFNotificationCenter.CenterType? {
29+
switch self {
30+
case CFNotificationCenterGetLocalCenter(): return .local
31+
case CFNotificationCenterGetDarwinNotifyCenter(): return .darwinNotify
32+
#if os(macOS)
33+
case CFNotificationCenterGetDistributedCenter(): return .distributed
34+
#endif
35+
default: return .none
36+
}
37+
}
38+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Observation.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/01/21.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
struct Observation {
12+
typealias SCFNotificationCallbackObjC = (CFNotificationCenter?, UnsafeMutableRawPointer?, CFNotificationName?, UnsafeRawPointer?, CFDictionary?) -> Void
13+
14+
let name: CFString
15+
var notificationName: CFNotificationName {
16+
.init(name)
17+
}
18+
19+
weak var observer: AnyObject?
20+
weak var object: AnyObject?
21+
22+
var observerPtr: UnsafeMutableRawPointer? {
23+
unsafeBitCast(observer, to: UnsafeMutableRawPointer?.self)
24+
}
25+
26+
var objectPtr: UnsafeRawPointer? {
27+
unsafeBitCast(object, to: UnsafeRawPointer?.self)
28+
}
29+
30+
let notify: SCFNotificationCallbackObjC
31+
32+
init<Observer, Object>(name: CFString, observer: Observer, object: Object?, notify: SCFNotificationCallback<Observer, Object>?) {
33+
self.name = name as CFString
34+
self.observer = observer as AnyObject?
35+
self.object = object as AnyObject?
36+
37+
self.notify = { center, observerPtr, name, objectPtr, userInfo in
38+
var observer: Observer?
39+
if let observerPtr {
40+
observer = unsafeBitCast(observerPtr, to: Observer?.self)
41+
}
42+
var object: Object?
43+
if let objectPtr {
44+
object = unsafeBitCast(objectPtr, to: Object?.self)
45+
}
46+
notify?(center, observer, name, object, userInfo)
47+
}
48+
}
49+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//
2+
// ObservationStore.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/01/21.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
class ObservationStore {
12+
static let shared = ObservationStore()
13+
14+
private(set) var localObservations = [Observation]()
15+
private(set) var darwinNotifyObservations = [Observation]()
16+
17+
#if os(macOS)
18+
private(set) var distributedObservations = [Observation]()
19+
#endif
20+
21+
private init() {}
22+
23+
func add(_ observation: Observation, center: SCFNotificationCenter.CenterType) {
24+
cleanUp()
25+
26+
switch center {
27+
case .local:
28+
localObservations.append(observation)
29+
case .darwinNotify:
30+
darwinNotifyObservations.append(observation)
31+
#if os(macOS)
32+
case .distributed:
33+
distributedObservations.append(observation)
34+
#endif
35+
}
36+
}
37+
38+
func remove(center: SCFNotificationCenter.CenterType, observer: UnsafeMutableRawPointer?, object: UnsafeRawPointer?) {
39+
cleanUp()
40+
41+
let observation: Observation?
42+
switch center {
43+
case .local:
44+
observation = localObservations
45+
.filterWith(observer: observer, object: object)
46+
.first
47+
localObservations = localObservations
48+
.remove(observer: observer, object: object)
49+
case .darwinNotify:
50+
observation = darwinNotifyObservations
51+
.filterWith(observer: observer, object: object)
52+
.first
53+
darwinNotifyObservations = darwinNotifyObservations
54+
.remove(observer: observer, object: object)
55+
#if os(macOS)
56+
case .distributed:
57+
observation = distributedObservations
58+
.filterWith(observer: observer, object: object)
59+
.first
60+
distributedObservations = distributedObservations
61+
.remove(observer: observer, object: object)
62+
#endif
63+
}
64+
65+
guard let observation else { return }
66+
CFNotificationCenterRemoveObserver(center.cfNotificationCenter, observation.observerPtr, observation.notificationName, observation.objectPtr)
67+
}
68+
69+
func removeEvery(center: SCFNotificationCenter.CenterType, observer: UnsafeMutableRawPointer?) {
70+
cleanUp()
71+
72+
let observation: Observation?
73+
switch center {
74+
case .local:
75+
observation = localObservations
76+
.filterWith(observer: observer)
77+
.first
78+
localObservations = localObservations
79+
.removeEvery(observer: observer)
80+
case .darwinNotify:
81+
observation = darwinNotifyObservations
82+
.filterWith(observer: observer)
83+
.first
84+
darwinNotifyObservations = darwinNotifyObservations
85+
.removeEvery(observer: observer)
86+
#if os(macOS)
87+
case .distributed:
88+
observation = distributedObservations
89+
.filterWith(observer: observer)
90+
.first
91+
distributedObservations = distributedObservations
92+
.removeEvery(observer: observer)
93+
#endif
94+
}
95+
96+
guard let observation else { return }
97+
CFNotificationCenterRemoveEveryObserver(center.cfNotificationCenter, observation.observerPtr)
98+
}
99+
100+
func cleanUp() {
101+
localObservations = localObservations.cleanUpped()
102+
103+
darwinNotifyObservations = darwinNotifyObservations.cleanUpped()
104+
}
105+
106+
func notifyIfNeeded(center: SCFNotificationCenter.CenterType, observer: UnsafeMutableRawPointer?, name: CFNotificationName?, object: UnsafeRawPointer?, userInfo: CFDictionary?) {
107+
cleanUp()
108+
109+
let observations: [Observation]
110+
switch center {
111+
case .local:
112+
observations = localObservations
113+
case .darwinNotify:
114+
observations = darwinNotifyObservations
115+
#if os(macOS)
116+
case .distributed:
117+
observations = distributedObservations
118+
#endif
119+
}
120+
121+
observations
122+
.filterWith(observer: observer, object: object)
123+
.forEach {
124+
$0.notify(center.cfNotificationCenter, observer, name, object, userInfo)
125+
}
126+
}
127+
128+
}

Sources/SCFNotification/SCFNotification.swift

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)