If you bridge a CFArrayRef of CFStringRefs to NSArray, can you treat the contents as NSStrings? - objective-c

Suppose I have a CFArrayRef containing CFStringRefs inside it and I bridge it over to NSArray using CFBridgingRelease(). Can I now treat the contents of the array as regular NSString instances and call all of the usual NSString methods?
If so, does this mean toll-free bridging happens recursively throughout the object when it's bridged? E.g. if I had a CFArray of CFArrays of CFDictionaries or something, they'd all be transparently converted to NSArray, NSDictionary, etc?

Toll free bridging does not involve any conversion (or there would be a cost), so talking about doing it recursively does not make sense.
What toll free bridging does in your case is determine who is responsible for managing the lifetime of the object - the programmer for the CF array, ARC for the NS array.
Further whether an object internally uses manual memory management or ARC is not important to the user of that object - they can use either style.
Combine the above and you have your answer: once you've handed your CF array of strings over to ARC your job is done.
HTH

CRD's answer is good and I've given it a +1. Here's a bit more explanation:
First, type-casting is a purely compile-time thing. And it doesn't cost anything. It just tells the compiler not to complain.
Toll-free casting of Core Foundation types to Cocoa types is because those objects are, under the hood, the same thing. The cast is just necessary to inform the compiler of that fact. Such a cast doesn't "do" anything. For example, in non-ARC code:
CFStringRef cfstring = /* ... */;
NSString* nsstring = (NSString*)cfstring;
That assignment is still just an assignment. The pointer value from cfstring is still just copied verbatim into the storage of nsstring. Nothing else happens.
Depending on how you obtained the CFString that cfstring was pointing to, you may have had a responsibility to release it. Since this is non-ARC, you still have that responsibility after it has been assigned to nsstring, which you can discharge either by calling CFRelease(cfstring) or [nsstring release] or [nsstring autorelease] when you're done with it. Once you do that, the value in both variables must be considered unusable as dangling pointers.
The case with ARC is only slightly different. An ARC bridging cast is also a compile-time thing, but it affects what code the compiler emits for automatic memory management. Since it has emitted different code, that technically has implications for run-time, but they are not related to the type-cast as such. The bridging cast tells the compiler whether it should emit retains or releases (or neither) of the object which is the subject of the expression. That's all; just a question of retaining or releasing the object. So, it has no effect on, say, objects within an array because those objects are not the subject of the expression, the array is. And it doesn't even do anything to the array beyond potentially retaining or releasing it.

Let me try and take a simpler approach to an answer:
A CFArrayRef can be treated as an NSArray* and vice versa.
A CFStringRef can be treated as an NSString* and vice versa.
Thus, an CFArray of CFStrings is an NSArray of NSStrings. You just need to cast it. (In so doing with __bridge_*, you also transfer the memory management to ARC.)

Related

Objc Cocoa MRC - Released and autoreleased objectsI have to write him up to see application

I'm writing a C++ application using Metal API (objective C) and MRC (Manual Reference Counting). I have a very limited experience with ObjC. Most of the Metal API objects are defined as protocols and created as an object returned from C-function or other object's method (ex. MTLDevice newBufferWithLength). To know how to release objects created this way I need to know if they have been set autoreleased or not (I can't call release an autoreleased object with retain count 1 for instance). The problem is I can't find any description in Metal API documentation which would answer this question. I've only read in user guide that all so called lightweight objects are created autoreleased. There are three examples of autoreleased objects but not sure if I can just assume that rest of the objects are not autoreleased. In cocoa many objects also may be created without alloc+init, being returned from a static method (ex NSString string) so the problem seems not to be only Metal related.
Thank you for your help.
The usual Objective-C rule is that creating scope is also responsible to release object. So, in virtually all cases, except well-documented exceptions, returned object is autoreleased (both returned through return value or out-arguments). More correct way to see it is that object is always returned with +0 scope-local retain count, so you are expected to retain it if needed. Reading the manual it seems that Metal API is one of Apple's frameworks, so it should follow this rule unless warned with bold statements. C functions in Objective-C are also expected to behave that way. (There is no difference between a method and a function in terms of resource management.)
For that "alloc-init vs. [NSString string]" part: MRC code either returns [NSString string], which is already +0, or [[[NSString alloc] init] autorelease]. Otherwise it breaks the convention. Exceptions are -[init] and +[new...] methods itself that return +1. Under ARC there is no difference between alloc-init/string, because ARC knows the convention and does the right thing, optimizing excessive retains/releases where possible.
Also note that -[retainCount] is meaningless and "considered harmful", because you never know how many retain-autorelease calls were performed and what objc-runtime accounting is in effect even with your own objects.
ARC is really a great option unless you're writing some sort of Objective-C -to- Whatever bridge, where retain counts and/or cycles must be managed explicitly due to lack of context. It doesn't take anything from you, giving in most cases a big advantage of not managing resources at all.

__bridge_transfer and performSelector:withObject:

I have a CFDictionaryRef that doesn't retain/release its objects. When I add an item in it, I take care of retaining it, and later :
NSMutableArray *array = (__bridge_transfer NSMutableArray *)CFDictionaryGetValue(...)
[self performSelector:someSelector withObject:array];
Where someSelector is a variable holding a selector I know about. Now, that second line makes Xcode tell the notorious warning:
PerformSelector may cause a leak because its selector is unknown
Does that mean I should worry about ARC not knowing how to manage memory for the array variable of which I just transferred ownership?
From a comment to the accepted answer of this question, it appears that somebody at Apple has confirmed this hypothesis (citing the answer itself):
In fact, there are times when memory management is tied to the name of the method by a specific convention. Specifically, I am thinking of convenience constructors versus make methods; the former return by convention an autoreleased object; the latter a retained object. The convention is based on the names of the selector, so if the compiler does not know the selector, then it cannot enforce the proper memory management rule.
Thus, it has nothing to do with a possible leak of arguments passed to the performSelector: call, but rather to its returned value, for which Objective-C has no way of knowing if it was autoreleased or not. This is also what Martin R from the comments was assuming.

Object release behavior in iPhone

If I release mainPath in following example the program gives an error (because I’m releasing an object with zero counter)
NSString *mainPath = [NSString stringWithFormat:#"%#/Documents/downloadFile.plist",NSHomeDirectory()];
NSLog(#"address is = %#",mainPath);
[mainPath release]; //Program failed here
But the following code works fine.
NSString *aa=#"hiiiii";
[aa release];
Can anyone explain this?
Actually I’m not clear about the pointer concept (give a suitable link to clear it)
Constant NSStrings are a special case. They are allocated statically at compile time and can't be deallocated. You can send release to a constant string as many times as you like, it'll never get deallocated. This is achieved in the current implementation by setting the retain count to INT_MAX which is treated as a special value meaning "don't decrement me on release".
You should read the Cocoa Memory Management Guide or at least the Objective-C Tutorial by Scott Stevenson. (Really. Do it, you’ll save a lot of time in the long run.) The difference is that the first string is autoreleased, you do not own it and should not release it. The second string is special, I think it’s not allocated on the heap at all and the release is essentially a no-op here.
String with format is a convenience method that autoreleases the string so in this case you are likely to be sending a release message to an already deallocated object.
In your second example, you are creating the string statically so retain counts don't apply.
You don't need to release your objects in either of those cases.
As a rule of thumb, if you didn't use init (or initWithFoo:) to create the object, and didn't deliberately use retain to retain the object (plus couple of other rarer cases), you don't need to use release.

Objective-C memory management: do you need to release string literals?

do you need to release something very simple this?
NSString *a = #"Hello";
//[a release]; ?
I come from a Java/C# world, and am confused about when things should be released/retained.
No. You only need to release objects you init/alloc yourself or your instance variables in your class dealloc method.
No, you do not need to release a constant NSString, though it doesn't cause any problems if you do. Constant strings are special case of the memory management system. Since their content is known at compile time, it is statically defined in the application binary itself, so it never has to be allocated or freed at runtime. For that reason, its retain and release methods are noops.
This is only true for constant NSStrings (strings that start with #), and their toll free bridged cousin, constant CFStrings (defined using the CFSTR() macro).

Pointers, am I using them correctly? Objective-c/cocoa

I have this in my #interface
struct track currentTrack;
struct track previousTrack;
int anInt;
Since these are not objects, I do not have to have them like int* anInt right?
And if setting non-object values like ints, boolean, etc, I do not have to release the old value right (assuming non-GC environment)?
The struct contains objects:
typedef struct track {
NSString* theId;
NSString* title;
} *track;
Am I doing that correctly?
Lastly, I access the struct like this:
[currentTrack.title ...];
currentTrack.theId = #"asdf"; //LINE 1
I'm also manually managing the memory (from a setter) for the struct like this:
[currentTrack.title autorelease];
currentTrack.title = [newTitle retain];
If I'm understanding the garbage collection correctly, I should be able to ditch that and just set it like LINE 1 (above)?
Also with garbage collection, I don't need a dealloc method right?
If I use garbage collection does this mean it only runs on OS 10.5+? And any other thing I should know before I switch to garbage collected code?
Sorry there are so many questions. Very new to objective-c and desktop programming.
Thanks
I have this in my #interface
struct track currentTrack;
struct track previousTrack;
int anInt;
Since these are not objects, I do not have to have them like int* anInt right?
That would declare a pointer to an int stored somewhere else.
And if setting non-object values like ints, boolean, etc, I do not have to release the old value right (assuming non-GC environment)?
release is a message. You can only send a message to a Cocoa (or, in some cases, Core Foundation) object.
The struct contains objects:
typedef struct track {
NSString* theId;
NSString* title;
More precisely, it contains pointers to objects.
You can't ever have an object stored directly in a variable; you can only allocate it dynamically by sending an alloc message to a class, and receive the pointer to the allocated instance. Similarly, you can only send a message to a pointer to an object; you cannot and should not dereference a pointer to an object.
For these reasons, we almost always elide the “a pointer to”. We speak of the pointers as if they are the objects, but, in precise truth, they are not.
} *track;
That's correct if you want to declare the track type as being a pointer to a struct track. Generally, this will confuse people.
Lastly, I access the struct like this:
[currentTrack.title ...];
currentTrack.theId = #"asdf"; //LINE 1
So the previous line is line 0? ;)
I'm also manually managing the memory (from a setter) for the struct like this:
[currentTrack.title autorelease];
currentTrack.title = [newTitle retain];
If I'm understanding the garbage collection correctly, I should be able to ditch that and just set it like LINE 1 (above)?
If you're using garbage collection, then the autorelease and retain messages will do nothing, so yes, the plain assignment and the assignment with (ineffectual) release and retain messages are equivalent.
I do question why you're putting this information in a structure and not a model object, though.
Also with garbage collection, I don't need a dealloc method right? If I use garbage collection does this mean it only runs on OS 10.5+? And any other thing I should know before I switch to garbage collected code?
Yes: Read the Garbage Collection Programming Guide. It tells you everything you need to know, including the answers to the previous two questions.
As for pointers, you may want to read my pointers tutorial. The title says C, but everything in C is also true in Objective-C.
Although you seem to understand this stuff all right in general, I'd strongly recommand against storing objects in a struct. Getting proper memory management for that will be very troublesome — because even though the struct itself doesn't require memory management, the objects still do, and unless the struct is only ever accessed through a function API (essentially making it s poor man's object), you're going to have a tough time ensuring that happens. Like Peter said, that makes sense to be a model object.
Correct, correct, no, yes, correct, yes, and Apple's Garbage Collection Programming Guide is a good read.