CFDictionaryGetValue what is the key?

Discussion in 'Mac Programming' started by Chirone, Jun 7, 2009.

  1. Chirone macrumors 6502

    Mar 2, 2009
    so i've spent the day struggling with CFDictionary... it's not as easy as NSDictinary too...

    i think i've put stuff into the dictionary:

    CFStringRef key = CFSTR("ChironesKey");
    NSString* val = [NSString stringWithFormat: @"%d", [aNumber intValue]];
    CFStringEncoding encoding = kCFStringEncodingMacRoman;
    const char *cstr_hello = [val UTF8String];
    CFAllocatorRef alloc_default = kCFAllocatorDefault; 
    CFStringRef value = CFStringCreateWithCString(alloc_default, cstr_hello, encoding);
    CFDictionaryRef info = CFDictionaryCreate(kCFAllocatorDefault, (const void **)key, (const void**)value, 2, NULL, NULL);
    (that's not the actual name of the key, i just did that so you know i'm using a string)
    so, i'm trying to store a number into this dictionary with a key.
    i think i've done this right, it's basically copy pasted from example code from Apple...

    the problem now is... i can't get the value out of it.

    i tried what i thought was correct:
    CFStringRef key = CFSTR("VQLineIndex");
    		const void* value = CFDictionaryGetValue(userInfo,key);
    but it turns out that value is null and doesn't exist...uh... didn't i put in the same key as i used to add the value?

    i tried numerous other ways too.

    i tried using this:
    CFTypeRef* values; 
    int size = CFDictionaryGetCount(userInfo);
    values = (CFTypeRef *) malloc( size * sizeof(CFTypeRef) );
    CFDictionaryGetKeysAndValues(userInfo, NULL, (const void **) values);
    const char* value = (const char*)values[0];
    this time value exists, but any attempt to do anything with it results in a runtime error that isn't caught by try-catch
    i've tried a few other ways too, but always i either get something that doesn't exist (as with the first example), or something that just causes an uncatchable error (as with the second example)

    i read that you can cast a CFDictionary to NSDictionary, so i tried:
    NSDictionary* val = (NSDictionary*)userInfo
    no compiler warning or errors but it came with runtime errors that you'd expect if you tried to cast something to something else that it cant cast too...

    anyone know the proper way to do this?
  2. kainjow Moderator emeritus


    Jun 15, 2000
    I'm not sure what userInfo is there, but if you have a CFDictionaryRef you can cast it to NSDictionary* and it'll work fine.

    This is what I've used before for creating a dictionary:
    CFMutableDictionaryRef entry = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    And then used CFDictionarySetValue() to add values.

    You can also use CFShow() to print a CFTypeRef struct to the console.
  3. gnasher729 macrumors P6


    Nov 25, 2005
    There is a multitude of severe bugs in your code.

    1. Why are you extracting a UTF-8 string from an NSString and then pass it to a CFString routine and claim that it is MacRoman? It isn't MacRoman, it is UTF8. Go to the header file where the constant for MacRoman was defined and find the correct encoding.

    2. Many CF objects and NS objects are toll-free bridged, which means that you can cast one to the other and use it. Take any NSString*, cast it to CFStringRef, and all the CFStringRef functions can be used and vice versa. No need at all to to copy the NSString* in a complicated way.

    3. Most people use just NULL instead of kCFAllocatorDefault.

    4. But the worst offender by far is your call to CFDictionaryCreate. CFDictionaryCreate creates an immutable dictionary, so all the keys and values must be passed in in the CFDictionaryCreate function. The keys and values could have any type, so they are passed in as void*. However, you want to be able to create dictionaries with more than one key/value pair (one key/value is kind of boring), so you pass in an array of of void*, or a pointer to void*, or a void**. If you have only one key/value pair, you can't pass the key and value itself, you pass the address where they are stored. And since you have _one_ key/value pair, you pass 1, not two.

    Furthermore, read the documentation of CFDictionaryCreate and check what the last two parameters should be when your keys and values are CF objects.

    So what actually happened is this: You had one CFStringRef containing a key, and one CFStringRef containing a value. You called CFDictionaryCreate and told it that you have two key/value pairs, and you told it that the first CFStringRef is actually a pointer to an array containing two keys, and the second CFStringRef is a pointer to an array containing two values. No wonder that it crashes.
  4. Chirone thread starter macrumors 6502

    Mar 2, 2009
    so i should really just be using mutable cf dictionaries?

    kainjow: sorry, userInfo is a CFDictionary from the CFNotification

    thanks for the tips, i wasn't sure how to print CF structs

    i did try casting it into an NSDictionary, but as i said, i was getting runtime errors that would occur if the method was non-existant

    gnasher: thanks for the analysis and assistance
    1- not sure... i don't actually have an excuse for this...

    2- i read about that, but somehow it wasn't working... i must have made a mistake in how i was casting... i can't remember what i did because i left the solution behind once it failed... i'll pay more attention to what i'm doing when casting between such things next time.

    3- oh.... i just used that because all the examples did

    4- so you're saying i told the dictionary it had 2 key/value pairs but it only one got passed into it and so that's why it crashed?

Share This Page