Skip to content

Instantly share code, notes, and snippets.

@mattmassicotte
Created October 25, 2023 15:14
Show Gist options
  • Save mattmassicotte/5f2450a64724ed9a70fbc935f4681a2d to your computer and use it in GitHub Desktop.
Save mattmassicotte/5f2450a64724ed9a70fbc935f4681a2d to your computer and use it in GitHub Desktop.
Use non-global actor protocols with global actor types
import AppKit
// Make a wrapper for the delegate that maps delegate methods to functions
// (Making it a class/inherit from NSObject as needed)
final class TextLayoutManagerDelegateAdapter: NSObject {
public typealias TextLayoutFragmentProvider = (_ location: NSTextLocation, _ textElement: NSTextElement) -> NSTextLayoutFragment
public let textLayoutFragmentProvider: TextLayoutFragmentProvider
public init(
textLayoutFragmentProvider: @escaping TextLayoutFragmentProvider
) {
self.textLayoutFragmentProvider = textLayoutFragmentProvider
}
}
// Add conformance to the MainActor-incompatible protocol,
// calling out to those function properties
extension TextLayoutManagerDelegateAdapter: NSTextLayoutManagerDelegate {
func textLayoutManager(
_ textLayoutManager: NSTextLayoutManager,
textLayoutFragmentFor location: NSTextLocation,
in textElement: NSTextElement
) -> NSTextLayoutFragment {
textLayoutFragmentProvider(location, textElement)
}
}
final class TextViewController: NSViewController {
// create the adapter in your MainActor type, accessing whatever internal methods you need
private lazy var delegateAdapter: TextLayoutManagerDelegateAdapter? = {
.init(textLayoutFragmentProvider: { self.textLayoutFragment(for: $0, in: $1) })
}()
init() {
super.init(nibName: nil, bundle: nil)
// finally, assign the delegate once self is inited
textView.textLayoutManager?.delegate = self.delegateAdapter
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment