Skip to content

Instantly share code, notes, and snippets.

@thomsmed
Created February 12, 2024 16:25
Show Gist options
  • Save thomsmed/8a97e68aa6ed082300b692b9c17e8062 to your computer and use it in GitHub Desktop.
Save thomsmed/8a97e68aa6ed082300b692b9c17e8062 to your computer and use it in GitHub Desktop.
Snippet showing how to configure a CFRunLoopObserver.
//
// RunLoopObserving.swift
//
import Foundation
func name(for thread: Thread) -> String {
if let name = Thread.current.name, !name.isEmpty {
return name
} else {
return Thread.isMainThread ? "main" : "<unknown>"
}
}
func addTimer(to runLoop: RunLoop) {
let timer = Timer(timeInterval: 5, repeats: true) { _ in
print("[Thread: \(name(for: .current)), Timer] Timer fired")
}
runLoop.add(timer, forMode: .default)
}
func observe(_ runLoop: RunLoop) {
var runLoopContext = CFRunLoopObserverContext(
version: 0,
info: nil,
retain: nil,
release: nil,
copyDescription: nil
)
guard let runLoopObserver = CFRunLoopObserverCreate(
kCFAllocatorDefault,
CFRunLoopActivity.allActivities.rawValue,
true,
0,
{ runLoopObserver, runLoopActivity, info in
switch runLoopActivity {
case CFRunLoopActivity.entry:
print("[Thread: \(name(for: .current)), CFRunLoopObserver] Run Loop Event: entry")
case CFRunLoopActivity.beforeTimers:
print("[Thread: \(name(for: .current)), CFRunLoopObserver] Run Loop Event: beforeTimers")
case CFRunLoopActivity.beforeSources:
print("[Thread: \(name(for: .current)), CFRunLoopObserver] Run Loop Event: beforeSources")
case CFRunLoopActivity.beforeWaiting:
print("[Thread: \(name(for: .current)), CFRunLoopObserver] Run Loop Event: beforeWaiting")
case CFRunLoopActivity.afterWaiting:
print("[Thread: \(name(for: .current)), CFRunLoopObserver] Run Loop Event: afterWaiting")
case CFRunLoopActivity.exit:
print("[Thread: \(name(for: .current)), CFRunLoopObserver] Run Loop Event: exit")
default:
assertionFailure("Unknown Run Loop Event")
}
},
&runLoopContext
) else {
return assertionFailure("Expected Observer creation to succeed")
}
CFRunLoopAddObserver(
runLoop.getCFRunLoop(),
runLoopObserver,
CFRunLoopMode.defaultMode
)
}
observe(.current)
addTimer(to: .current)
let thread = Thread {
Thread.current.name = "worker"
print("Started Thread: \(name(for: .current))")
observe(.current)
addTimer(to: .current)
RunLoop.current.run()
print("Exiting Thread: \(name(for: .current))") // Never called
}
thread.start()
RunLoop.current.run()
print("Exiting Thread: \(name(for: .current))") // Never called
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment