ARTICLE AD BOX
I'm working on a macOS app that uses Apple's private MultitouchSupport.framework to intercept raw trackpad touch data. The framework uses C-style callbacks that fire on an internal background thread (mt_ThreadedMTEntry). I'm trying to achieve Swift 6 strict concurrency compliance but running into challenges with the callback pattern.
// Private API bindings using @_silgen_name typealias MTDeviceRef = UnsafeMutableRawPointer typealias MTContactCallbackFunction = @convention(c) ( MTDeviceRef?, UnsafeMutableRawPointer?, // Pointer to touch data array Int32, // Number of touches Double, // Timestamp Int32 // Frame number ) -> Int32 @_silgen_name("MTDeviceStart") func MTDeviceStart(_ device: MTDeviceRef, _ mode: Int32) @_silgen_name("MTRegisterContactFrameCallback") func MTRegisterContactFrameCallback(_ device: MTDeviceRef, _ callback: MTContactCallbackFunction)Registering the callback:
// C-convention callback — fires on framework's internal thread (mt_ThreadedMTEntry) let callback: MTContactCallbackFunction = { device, touches, count, timestamp, frame in guard let touches = touches else { return 0 } MultitouchManager.shared.deviceDidReceiveTouches(touches, count: count) return 0 } // During setup: if let device = MTDeviceCreateDefault() { MTRegisterContactFrameCallback(device, callback) MTDeviceStart(device, 0) }My current approach uses @unchecked Sendable conformance with internal locking:
final class MultitouchManager: @unchecked Sendable { private let fingerCountLock = NSLock() private var _currentFingerCount: Int = 0 var currentFingerCount: Int { get { fingerCountLock.lock() defer { fingerCountLock.unlock() } return _currentFingerCount } set { fingerCountLock.lock() defer { fingerCountLock.unlock() } _currentFingerCount = newValue } } private let gestureQueue = DispatchQueue(label: "com.app.gesture", qos: .userInteractive) }My Question:
Is @unchecked Sendable the right approach here? The framework's callback gives us no control over which thread it uses, and we can't mark the C function type as @Sendable.
Environment: macOS 15+, Swift 6.0, Xcode 16+
Note: I'm aware this uses private APIs. This is for a utility app distributed outside the App Store.
