Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

darkandlong

macrumors member
Original poster
Jun 19, 2008
64
212
Uk
I'm struggling to find any explanation for why CFDictionary methods return consts. Can anyone explain this to me?
 
I'm struggling to find any explanation for why CFDictionary methods return consts. Can anyone explain this to me?

Think about where the value originates that CFDictionary returns. Do you know whether that value was const or not? What is safer, if CFDictionary returns a const void* or if it returns a void*?
 
Thanks for replying. I am quite new to the language, so please could you expand on your answer a little. Specifically I am trying to understand how to deal with the value returned to avoid a compiler warning:

Initialization discards qualifiers from pointer target type

I can get rid of the warning by doing the following:

Code:
id const someValue = CFDictionarySetValue(self.mappingConfigByMediatedObjectClass, mediatedObjectClass, mediatorMapping);

But I want to understand why this is necessary. Why must I declare a local const variable?
 
Is there any reason why you're using CFDictionary instead of NSDictionary?

But your posted code is confusing. CFDictionarySetValue doesn't return anything. CFDictionaryGetValue returns something, but only take 2 paramaters.
 
Sorry. Was very early in the morning.

I am using CFMutableDictionary because I need to use keys that are not copied. I am programming in cocoa touch so this is unfortunately my only option as I have no access to NSHashTable.

The correct code should have been:

id<SomeProtocol> someObject = CFDictionaryGetValue(self.someDictionary, someObjectAsKey);

So if I set someObject as a const I lose the warning.
 
Sorry. Was very early in the morning.

I am using CFMutableDictionary because I need to use keys that are not copied. I am programming in cocoa touch so this is unfortunately my only option as I have no access to NSHashTable.

The correct code should have been:

id<SomeProtocol> someObject = CFDictionaryGetValue(self.someDictionary, someObjectAsKey);

So if I set someObject as a const I lose the warning.

I would very strongly suggest that if you are new to this, you should _not_ use CFDictionary. It can be tricky to set up, and you need to thoroughly understand it and get it right, especially if you use it to do something that NSDictionary cannot do.

You will be much better off with a design where both keys and objects are NSObject and where you can use NSDictionary. (And an NSDictionary will _retain_ keys and objects, it will not copy anything).


But I want to understand why this is necessary. Why must I declare a local const variable?

The rule is: The language should not allow you to modify a constant value unless you explicitly write something that makes it possible (and the consequences are your fault). CFDictionary cannot know whether you use it to store a const or non-const item. Therefore CFDictionaryGetValue cannot return a non-const pointer, because you could put a pointer to a const object into the dictionary, get a non-const pointer back with CFDictionaryGetValue, and use it to modify the constant data. It is _designed_ to not allow you to do that.

The assignment to the local variable gave you a warning; exactly for that reason. To remove the warning, you have to explicitly cast the result of CFDictionaryGetValue. That basically tells the compiler "Shut up, I know what I'm doing, if it goes wrong it's all my fault".
 
Last edited:
I'm certainly not enjoying my time with CFDictionary so far ;) However, as far as I understand it NSDictionary/NSMutableDictionary will always copy keys. With the CFDictionary I can specify whether I want the keys to be copied when I create it, but with NSDictionary I have no choice.

The objects I am using as keys are too heavy to be copied and I cannot guarantee they will support NSCopying anyway.

The assignment to the local variable gave you a warning; exactly for that reason. To remove the warning, you have to explicitly cast the result of CFDictionaryGetValue. That basically tells the compiler "Shut up, I know what I'm doing, if it goes wrong it's all my fault".

Thanks. This makes a lot of sense. But how do I cast in this context as I'm not casting to a type, I'm casting a const to be not-a-const?

----------

Ok. So it seems I can just cast it without the const like this:

Code:
id<SomeProtocol> someObject = (id<SomeProtocol>)CFDictionaryGetValue(self.someDictionary, someObjectAsKey);

Which will suppress the warning. Many thanks for your help.
 
Last edited by a moderator:
The values that you put into the CFDictionary are const void * so it only makes sense that the values to retrieve from it are the same. Use of this type is a guarantee by the container that it isn't going to modify the value that you add to the container. Since you can't do anything useful with a const void * anyway you must cast it to another type. So casting it in such a way that you remove the const is not a burden.

In general const isn't very useful in objective-C since all the Foundation Classes (most or all) come in mutable and immutable versions. Using the immutable type serves the same purpose that const serves in some other languages.
 
I'm certainly not enjoying my time with CFDictionary so far ;) However, as far as I understand it NSDictionary/NSMutableDictionary will always copy keys. With the CFDictionary I can specify whether I want the keys to be copied when I create it, but with NSDictionary I have no choice.

You should be able to create a CFDictionaryRef with your own retain and release callbacks and then use toll-free bridging to cast that CFDictionaryRef as an NSDictionary. You should be able to treat it like any other Cocoa dictionary, except that it should respect your custom callbacks. I have not done a ton of work with Core Foundation, but you might want to give that a try.
 
Thanks for the replies.

@dejo They are ViewControllers

@North Bronson Thats what I've ended up doing. Dangerous though. casting is to NSMutableDictionary and using setObject:ForKey: still causes the key to be copied, so adding items has to be done without the cast.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.