Search code examples
objective-cswiftmacoscore-foundation

CFDictionaryGetValue throws EXC_BAD_ACCESS


I found a code snipped from Getting graphic card information in objective C in Objective-C and I am currently trying to convert it to Swift. I am trying to read a value from a CFMutableDictionary (code is below). However when I call the function CFDictionaryGetValue I get an error: "Thread 1: EXC_BAD_ACCESS (code=1, address=0x656d614e4f60)"

Here is my current code:

static func getGpuName() {
        var iterator: io_iterator_t = 0
        let errCode: kern_return_t  = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOPCIDevice"), &iterator)
        if errCode != kIOReturnSuccess {
            fatalError("Could not retrieve the service dictionary of \"IOPCIDevice\"")
        }

        // iterate over the pci devices
        var device = IOIteratorNext(iterator)
        while device != 0 {
            var unmanagedServiceDictionary: Unmanaged<CFMutableDictionary>?
            if IORegistryEntryCreateCFProperties(device, &unmanagedServiceDictionary, kCFAllocatorDefault, 0) != kIOReturnSuccess {
                IOObjectRelease(device)
                continue
            }

            if let serviceDictionary: CFMutableDictionary = unmanagedServiceDictionary?.takeRetainedValue() {
                let name = CFDictionaryGetValue(serviceDictionary, "IOName")
            }

            // release the device
            IOObjectRelease(device)

            // get the next device from the iterator
            device = IOIteratorNext(iterator)
        }
}

Does anybody have an idea how I can read the value of the CFMutableDictionary?

Thanks :)


Solution

  • Handling the CoreFoundation API is a real pain.

    The error occurs because you cannot pass a literal String as second parameter of CFDictionaryGetValue which must be a UnsafeRawPointer.

    However the solution is pretty easy. Cast the dictionary to a Swift dictionary

    if let serviceDictionary = unmanagedServiceDictionary?.takeRetainedValue() as? [String:Any] {
        if let name = serviceDictionary["IOName"] as? String {
            print(name)
        }
    }