Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
The short answer is that you can (see Dave DeLongs answer). The long answer is that you can't. Both are true. A better question might be "Why do you need to know?" In my opinion, if you can arrange things so that you don't need to know, you're probably going to be better off.
I'm not saying that you can't do it, or even that you shouldn't. What I am saying is that there are some hidden gotchas when you start down this path, and some times you're not really aware of what all the unstated assumptions are. Unfortunately, programming
correctly
depends on knowing all the little details. Off the top of my head, here's a few of the potential gotchas:
To the best of my knowledge the set of Core Foundation types has increased in each major OS release. Therefore each major OS release has a superset Core Foundation types of the previous releases, and likely a strict superset at that. This is "observed behavior", and not necessarily "guaranteed" behavior. The important thing to note is that "things can and do change", and all things being equal, the easier and simpler solutions tend not to take this in to account. It is generally considered poor programming style to code something that breaks in the future, regardless of the reason or justification.
Because of Toll-Free Bridging between Core Foundation and Foundation, just because a
CFTypeRef = CFStringRef
does not mean that a
CFTypeRef ≡ CFStringRef
, where
=
means "equal to" and
≡
means "identical to". There is a distinction, which may or may not be important depending on context. As a warning, this tends to be where the bugs roam freely.
For example, a
CFMutableStringRef
can be used where ever a
CFStringRef
can be used, or
CFStringRef = CFMutableStringRef
. However, you can not use a
CFStringRef
everywhere a
CFMutableStringRef
can be used for obvious reasons. This means
CFStringRef ≢ CFMutableStringRef
. Again, depending on the context, they can be equal, but they are not identical.
It is
very
important to note that while there is a
CFStringGetTypeID()
, there is no corresponding
CFMutableStringGetTypeID()
.
Logically,
CFMutableStringRef
is a strict superset of
CFStringRef
. It would follow, then, that passing a bona fide immutable
CFStringRef
to a
CFMutableString
API call would cause "some kind of problem". While this may not be true now (i.e., 10.6), I know for a fact that the following was true in the past: The
CFMutableString
API calls did not verify that "the string argument" was actually mutable (this was actually true for all types that made a distinction between immutable and mutable). The checks were there, but they were in the form of debug assertions that were disabled on "Release" builds (in other words, the checks were never performed in practice).
This is (or possibly was) officially not considered to be a bug, and the (
trivial
) mutability checks were
not
done "for performance reasons". No "public" API is provided to tell the mutability of a
CFString
pointer (or mutability of any type). Combined with Toll-Free bridging, this meant that you could mutate immutable
NSString
objects, even though the
NSMutableString
APIs did perform a mutability check and caused "some kind of problem" when trying to mutate an immutable object. Flavor with the fact that
@""
constant strings in your source are mapped to read-only memory at run time.
The official line, as I recall, was "not to pass immutable objects, either CFStringRef or NSString, to CFMutableString API's, and further more, it was a bug to do so". When it was pointed out that there might be some security related issues with this stance (never mind the fact that it was fundamentally impossible), say if anything ever made the mistake of critically depending on the immutability of a string, especially "well known" strings, the answer was "the problem is theoretical and nothing will be done at this time until a workable exploit can be demonstrated."
Update:
I was curious to see what the current behavior is. On my machine, running 10.6.4, using
CFMutableString
API's on an immutable
CFString
causes the immutable string to become essentially
@""
, which is at least better than what it did before (<= 10.5) and actually mutate the string. Definitely not the ideal solution, has that bitter real world taste to it where its only redeeming quality is that it is "the least worst solution".
So remember, be careful in your assumptions! You can do it, but if you do, it's more important that you
not
do it
wrong
. :) Of course, a lot of "wrong" solutions will work, so the fact that things are working is not necessarily proof that you're doing it right. Good times!
Also, in a
Duck Typed
system it is often considered bad form, and possibly even a bug, to "look too closely at the type of an object". Objective-C is definitely a Duck Typed system and this unquestionably bleeds over in to Core Foundation due to the tight coupling of Toll-Free bridging.
CFTypeRef
is a direct manifestation of this Duck Type ambiguity, and depending heavily on the context, may be an explicit way of saying "You are not supposed to be looking too closely at the types".
–
If you want to find out what type a
CFTypeRef
is during development, you can use the following snippet.
printf("CFTypeRef type is: %s\n",CFStringGetCStringPtr(CFCopyTypeIDDescription(CFGetTypeID(myObjectRef)),kCFStringEncodingUTF8));
This will print a human readable name for the type so you know what it is. But Apple makes no guarantees that they'll keep these descriptions consistant so don't use this in production code. (As is the snippet will leak memory but you should only use it during development anyway so who cares).
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.