Search code examples
swiftpointersmacos-carbon

Swift UnsafeMutableRawPointer returns class instead of instance


I’d expect this code to return an NSString with the ID of the currently selected input source. Instead, it seems to return one of the NSString classes itself.

import Foundation
import Carbon

let current = TISCopyCurrentKeyboardInputSource().takeUnretainedValue()

let id = TISGetInputSourceProperty(current, kTISPropertyInputSourceID).load(as: NSString.self)
id.length

When I run this in my macOS app, I get this error message in the logs: +[__NSCFConstantString _fastCStringContents:]: unrecognized selector sent to class 0x7fff92cf79e8. How can I fix this issue so I get the correct returned value?


Solution

  • TISGetInputSourceProperty() returns an (unmanaged) raw pointer which must be converted to a CFStringRef, not dereferenced with load(). The CFString can then be bridged to a Swift String.

    let current = TISCopyCurrentKeyboardInputSource().takeRetainedValue()
    if let ptr = TISGetInputSourceProperty(current, kTISPropertyInputSourceID) {
        let id = Unmanaged<CFString>.fromOpaque(ptr).takeUnretainedValue() as String
        print(id) // com.apple.keylayout.German
    }
    

    Note also that takeRetainedValue() must be used on the return value of TISCopyCurrentKeyboardInputSource() because that function returns a (+1) retained reference, otherwise you'll have a memory leak.