When I pass a C-array to an Objective-C method, is it sufficient to let the method copy the array to heap memory? [duplicate] - objective-c

This question already has answers here:
Am I correctly creating and passing this C array to Objective-C method and referencing it with a property?
(3 answers)
Closed 9 years ago.
Example:
unsigned char colorComps[] = {2, 3, 22, 55, 9, 1};
Passing this to an Objective-C method which references it with a property. It needs to be copied to heap memory first. But is it fine to let the method do this step or must I copy it to heap before passing it to the method, for safety?

In pretty much every C API I've used, the convention is that the called function is responsible for copying data if needed.
This makes sense, as the called function knows how long the data will be needed, whereas the caller doesn't. Since we generally use C for performance reasons, this also avoids unnecessary memory allocation and copying.
On that note, unless you've got performance reasons for using a C array, just use an NSArray of NSNumbers. Much simpler.

The exact same rules as with pass an array to a C function apply. There is no special handling in Objective-C regarding C arrays. Except that you can't declare a property with a C array type. For workarounds see this question and this question. In this case, your object (which wants to expose the array) should allocate the memory, copy the array and release it when appropriate. It's a bad idea to allocate it "outside" but then release it "inside".
Unless you really need a C array (for example, because you've got a third party library that wants it as argument and you'd need to construct it all the time) you should stick with Objective-C objects (NSNumbers in NSArrays). Especially since the syntax is now pretty straight forward:
NSArray *myArray = #[ #(1), #(42), #(543) ];
Using C arrays just "because they're faster" would be pre-mature optimization unless you have actually measured that an NSArray/NSNumber solution is a bottleneck for you. I'm doing multimedia processing on iOS and I've never had to switch from an NSArray to a C array for performance reasons.

I believe you're asking about my comment on your previous question, so let me explain.
If you simply take whatever array you receive and keep it as-is, you have no control over it; you're leaving the integrity of your code entirely to the calling function. You may accidentally forget to pass in a copy, or you pass in a string literal*, and then you have a potentially difficult-to-find bug. By using a property and setting the ivar to an array that you created, you are in control of it. You know precisely its desired lifetime, and you know it's safe (indeed, required) to free it in dealloc.
Note that this is the reason why block properties should always be declared copy. If you just keep the block around as you received it, it will be invalid and lead to problems later on unless it was already copied to the heap at some point. But you don't normally copy a block when you are passing it to a function, the function you call is responsible for making sure it's safe to keep around.
*: Yes, unlikely the way you're using it, but under different circumstances it could be a concern.

Related

objective-c memory management--how long is object guaranteed to exist?

I have ARC code of the following form:
NSMutableData* someData = [NSMutableData dataWithLength:123];
...
CTRunGetGlyphs(run, CGRangeMake(0, 0), someData.mutableBytes);
...
const CGGlyph *glyphs = [someData mutableBytes];
...
...followed by code that reads memory from glyphs but does nothing with someData, which isn't referenced anymore. Note that CGGlyph is not an object type but an unsigned integer.
Do I have to worry that the memory in someData might get freed before I am done with glyphs (which is actually just pointing insidesomeData)?
All this code is WITHIN the same scope (i.e., a single selector), and glyphs and someData both fall out of scope at the same time.
PS In an earlier draft of this question I referred to 'garbage collection', which didn't really apply to my project. That's why some answers below give it equal treatment with what happens under ARC.
You are potentially in trouble whether you use GC or, as others have recommended instead, ARC. What you are dealing with is an internal pointer which is not considered an owning reference in either GC or ARC in general - unless the implementation has special-cased NSData. Without that owning reference either GC or ARC might remove the object. The problem you face is peculiar to internal pointers.
As you describe your situation the safest thing to do is to hang onto the real reference. You could do this by assigning the NSData reference to either an instance variable or a static (method local if you wish) variable and then assigning nil to that variable when you've done with the internal pointer. In the case of static be careful about concurrency!
In practice your code will probably work in both GC and ARC, probably more likely in ARC, but either could conceivably bite you especially as compilers change. For the cost of one variable declaration and one extra assignment you avoid the problem, cheap insurance.
[See this discussion as an example of short lifetime under ARC.]
Under actual, real garbage collection that code is potentially a problem. Objects may be released as soon as there is no longer any reference to them and the compiler may discard the reference at any time if you never use it again. For optimisation purposes scope is just a way of putting an upper limit on that sort of thing, not a way of dictating it absolutely.
You can use NSAllocateCollectable to attach lifecycle calculation to C primitive pointers, though it's messy and slightly convoluted.
Garbage collection was never implemented in iOS and is now deprecated on the Mac (as referenced at the very bottom of this FAQ), in both cases in favour of automatic reference counting (ARC). ARC adds retains and releases where it can see that they're implicitly needed. Sadly it can perform some neat tricks that weren't previously possible, such as retrieving objects from the autorelease pool if they've been used as return results. So that has the same net effect as the garbage collection approach — the object may be released at any point after the final reference to it vanishes.
A workaround would be to create a class like:
#interface PFDoNothing
+ (void)doNothingWith:(id)object;
#end
Which is implemented to do nothing. Post your autoreleased object to it after you've finished using the internal memory. Objective-C's dynamic dispatch means that it isn't safe for the compiler to optimise the call away — it has no way of knowing you (or the KVO mechanisms or whatever other actor) haven't done something like a method swizzle at runtime.
EDIT: NSData being a special case because it offers direct C-level access to object-held memory, it's not difficult to find explicit discussions of the GC situation at least. See this thread on Cocoabuilder for a pretty good one though the same caveat as above applies, i.e. garbage collection is deprecated and automatic reference counting acts differently.
The following is a generic answer that does not necessarily reflect Objective-C GC support. However, various GC implementaitons, including ref-counting, can be thought of in terms of Reachability, quirks aside.
In a GC language, an object is guaranteed to exist as long as it is Strongly-Reachable; the "roots" of these Strong-Reachability graphs can vary by language and executing environment. The exact meaning of "Strongly" also varies, but generally means that the edges are Strong-References. (In a manual ref-counting scenario each edge can be thought of as an unmatched "retain" from a given "owner".)
C# on the CLR/.NET is one such implementation where a variable can remain in scope and yet not function as a "root" for a reachability-graph. See the Systems.Timer.Timer class and look for GC.KeepAlive:
If the timer is declared in a long-running method, use KeepAlive to prevent garbage collection from occurring [on the timer object] before the method ends.
As of summer 2012, things are in the process of change for Apple objects that return inner pointers of non-object type. In the release notes for Mountain Lion, Apple says:
NS_RETURNS_INNER_POINTER
Methods which return pointers (other than Objective C object type)
have been decorated with the clang compiler attribute
objc_returns_inner_pointer (when compiling with clang) to prevent the
compiler from aggressively releasing the receiver expression of those
messages, which no longer appear to be referenced, while the returned
pointer may still be in use.
Inspection of the NSData.h header file shows that this also applies from iOS 6 onward.
Also note that NS_RETURNS_INNER_POINTER is defined as __attribute__((objc_returns_inner_pointer)) in the clang specification, which makes it such that
the object's lifetime will be extended until at least the earliest of:
the last use of the returned pointer, or any pointer derived from it,
in the calling function;
or the autorelease pool is restored to a
previous state.
Caveats:
If you're using anything older then Mountain Lion or iOS 6 you will still need to use any of the methods discussed here (e.g., __attribute__((objc_precise_lifetime))) when declaring your local NSData or NSMutableData objects.
Also, even with the newest compiler and Apple libraries, if you use older or third party libraries with objects that do not decorate their inner-pointer-returning methods with __attribute__((objc_returns_inner_pointer)) you will need to decorate your local variables declarations of such objects with __attribute__((objc_precise_lifetime)) or use one of the other methods discussed in the answers.

Storing Blocks in an Array

In Objective-C, I know that blocks are considered objects, so I was wondering if it was possible to store them in an array. This begs the question, are blocks first class objects or are they just treated like objects for the sake of passing them between objects? If they are first class objects, then shouldn't they be storable in arrays?
EDIT: Without going into too much detail, under ARC, you can now add blocks to collections like any other object (see discussion).
I've left the original answer intact below, since it contains some interesting technical details.
This begs the question, are blocks first class objects or are they
just treated like objects for the sake of passing them between
objects? If they are first class objects, then shouldn't they be
storable in arrays?
Blocks are Objective-C objects that very much behave like every other NSObject, with a couple of key differences:
Blocks are always generated by the compiler. They are effectively "alloc/init"ed at runtime as execution passes over the blocks declaration.
Blocks are initially created on the stack. Block_copy() or the copy method must be used to move the Block to the heap if the Block is to outlive the current scope (see ARC point below).
Blocks don't really have a callable API beyond memory management.
To put a Block into a Collection, it must first be copied. Always. Including under ARC. (See comments.) If you don't, there is risk that the stack allocated Block will be autoreleased and your app will later crash.
Copying a stack based block will copy all of the captured state, too. If you are making multiple copies of a block, it is more efficient to copy it once, then copy the copy (because copying the copy just bumps the retain count since Blocks are immutable).
Under ARC, returning a Block from a method or function "just works"; it'll be automatically copied to the heap and the return will effectively be an autoreleased Block (the compiler may optimize away the autorelease in certain circumstances). Even with ARC, you still need to copy the block before sticking it into a collection.
I've written a couple of blog posts both providing an introduction to blocks and some tips and tricks. You might find them interesting.
And, yes, adding 'em to dictionaries is quite useful. I've written a couple of bits of code where I dropped blocks into dictionaries as command handlers where the key was the command name. Very handy.
Yes, blocks are indeed objects, and you can put them in arrays:
NSMutableArray *arr = [NSMutableArray new];
[arr addObject:^(){NSLog(#"my block");}];
void (^ myblock)() = [arr objectAtIndex:0];
myblock();
this will put the "my block" in the console.

Is this safe? (pointers to Objective C instance variables )

I have some C functions that need access Instance variables. I already pass a struct in as an argument to the function, so I added pointers to the ivars to the struct.
Is it safe to rely on the pointer remaining valid throughout the life of the app (assuming i retain and release sensibly?)
The pointer remains valid as long as the thing it points to remains valid. If the object that contains the ivars gets dealloced, and someone else is still trying to use a pointer to one of the ivars, then yeah, it'll blow up.
That said, it might be a better design to just get and set the actual values as necessary; surely the ivars aren't so big that you need to point directly to them. Doing so breaks all notion of encapsulation and requires you to do a lot more error-prone work to make sure all your object lifetimes coincide. Feel free to say more or ask another question if you want more broad design advice.

C array vs Obj-C array

When an array is created in Objective-C using alloc init, how is the memory managed when objects are added to the array?
I would like to know how this relates to C when you create an array and malloc, the allocated size needs to be the size of the expected array or the array memory needs to be reallocated.
How do these relate or what is a good way to understand the way the C code works.
Does the objective-c arrays memory get handled internally when objects are added or how does this work?
An Objective-C array follows the same memory management rules as other Objective-C objects. If you allocate it, you'll need to release it.
C arrays and Objective-C arrays are similar in concept, but implemented quite differently. A C array is a contiguous block of memory with very little other than a language construct governing how you use it. Objective-C arrays are objects with significant built-in functionality. They dynamically resize themselves (if they're mutable) to accomodate added elements. They properly retain and release the objects that they store. They can sort themselves, filter themselves, insert objects, delete objects, etc. You should make no assumptions about how they're implemented.
Apple's documentation should give you a much better idea of what's possible with Objective-C arrays (and while you're at it, look at the other collection classes too). Start reading here:
Collections Programming Topics
NSArrays (And by extension NSMutableArrays) retain the objects added to them, and send them all release messages when the array itself is deallocated.
The upshot of this is that a common pattern is to alloc an object, initialize it, hand it to the array, and then release it. Since the array retains it for itself, it'll last as long as the array itself does, or until you instruct the array to get rid of it. You will never need to send it another release message, the array machinery takes care of that.
I'd guess that the Mutable arrays are implemented as something like a linked list, so they can be easily expanded and contracted later. It's just a list of pointers, and maybe a little metadata. Since it doesn't create any objects handed to it, just puts it's own leash on them, all it needs to do it have a place for the pointer to the object.

NSCopyObject considered harmful?

In the Xcode documentation for NSCopyObject, the special considerations section states:
This function is dangerous and very difficult to use correctly. It's use as part of copyWithZone: by any class that can be subclassed, is highly error prone. Under GC or when using Objective-C 2.0, the zone is completely ignored.
This function is likely to be deprecated after Mac OS X 10.6.
Why is it difficult to use correctly? It performs a shallow (bit-for-bit) copy. Objects are not copied or retained. The documentation is pretty clear on this.
If I'm not missing other reasons, what is the preferred alternative for performing a shallow copy of an object?
Edit:
There are valid reasons to want to perform a shallow copy. One example: a class may have many instance variables, most of which are primitive types (integer, float) or objects that are intentionally not retained to avoid retain cycles (delegates). A shallow copy using NSCopyObject copies all of these in one nice, self-documenting line of code. Any remaining ivars that do need to be reference counted can be retained or copied individually.
The alternative to this is to either assign to the new object using pointer syntax (newObject->ivar = ivar) or to create an init method with a potentially large number of arguments (one for each ivar to copy). The latter strikes me as especially ugly, but I suppose it doesn't need to be in the header and exposed to the world.
You shouldn't make a shallow copy not involving the correct retain/release. Period.