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.
Related
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.
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.
Let's suppose I create a few objects and I add them to an array.
House *myCrib = [House house];
House *johnHome = [House house];
House *lisaHome = [House house];
House *whiteHouse = [House house];
NSArray *houses = [NSArray arrayWithObjects: myCrib, johnHome, lisaHome, whiteHouse, nil];
Normally, all House objects have a retain count of two, but they're being autoreleased once. After a while, I decide to release myCrib, even if I'm not the owner — I never retained or initialized.
[myCrib release];
The retain count should drop to zero and my object should be deallocated. My question now is: will this illegal action cause my app to work erroneously or even crash, or will NSArray simply delete my object from its list with bad consequences.
I'm looking for a way to maintain a list of objects, but I want the list to maintain itself. When some object disappears, I want the reference to it to disappear from my array gracefully and automatically. I'm thinking of subclassing or wrapping NSArray.
Thank you.
My question now is: will this illegal
action cause my app to work
erroneously or even crash, or will
NSArray simply delete my object from
its list with bad consequences.
Your array now has an invalid object pointer. There's no way to tell that the pointer is invalid just by looking at it, and the array isn't notified that the object has been deallocated. The problem isn't with the array, after all, the problem is with the code that improperly releases the object. So yes, the application will likely crash or otherwise behave incorrectly due to that bad pointer, and no, NSArray won't detect and deal with the problem for you.
I'm looking for a way to maintain a
list of objects, but I want the list
to maintain itself. When some object
disappears, I want the reference to it
to disappear from my array gracefully
and automatically.
If the objects in the list are all instances of a common class, you could define your own memory management methods that both retain/release the object and add/remove it from the list, or broadcast appropriate notifications in case there can be multiple lists. I suppose you could even override -retain and -release for this purpose, but I'd think long and hard about that before doing it, and document it well if you do; it's not the sort of thing that other developers would expect.
Another option might be Core Data. If you delete a managed object from the object graph, it'll disappear from any relationships. Strictly speaking, a to-many relationship is a set, not a list, but the difference may not be a concern for your purposes.
Update: I just noticed that you didn't tag your question ios. If you're working under MacOS X, you should definitely take a look at NSPointerArray. If you use garbage collection, NSPointerArray can be configured to use weak references and to replace references to collected objects with null references. This is exactly what you seem to be looking for.
You should not release myCrib if you are not the owner. To do so is a violation of the memory management guidelines and will make your code extremely difficult to maintain. I cannot stress enough that you absolutely should never do this under any sort of circumstance. You're asking for crashes; the array has declared ownership of the object, and you must not subvert that ownership in any way.
So the answer here is: your code is absolutely wrong and you should fix it. If you can't fix it, you should trash it and start over and keep rewriting it until you've come up with another way to achieve the same effect without subverting object ownership. I guarantee that it's possible.
If what you want is a weak-referencing array, then there are a couple ways you can do this (this was just asked a couple of days ago):
NSPointerArray - weakly references its pointers. When you use garbage collection, they're autozeroing (ie, the pointers get removed when the object is deallocated). Unfortunately, this is not available on iOS.
CFMutableArrayRef - you can specify a custom retain and release callback, or just not specify one at all. If you leave them out, the array will simply not retain the objects it contains. However, this does not automatically remove the pointer when the object is deallocated.
DDAutozeroingArray - an NSMutableArray subclass I wrote the other day to provide a weakly-referencing and auto-zeroing array that works on both Mac OS and iOS. However, I strongly encourage you to use this only as a last resort; There are probably much better ways of doing what you're looking for. https://github.com/davedelong/Demos
I'm looking for a way to maintain a
list of objects, but I want the list
to maintain itself. When some object
disappears, I want the reference to it
to disappear from my array gracefully
and automatically. I'm thinking of
subclassing or wrapping NSArray.
If I have understood right, what you want is an array of weak references. Then, you might be interested in reading this post.
You're asking for a crash here. Your NSArray will still have a reference to the object that now no longer exists -- and who knows what it will be pointing to after a while?
Subclassing NSArray might not be the answer either. It's a class cluster which, in short, means that it's harder to subclass than you might hope.
Not entirely sure how you'd implement this. Something like the element sending a notification when they're about to be deallocated which the array would then pick up. You'd need to be careful that you didn't leak or over-release your objects.
I created a wrapper class — in my code it's called a controller — which maintains the (mutable) array for me. I initialize the controller class in my view controllers — the place where I need them — instead of using an array directly.
No invalid code for me. :-p
I'm starting to code in objective-c and I've just realized that objects can only be passed by reference.
What if I need an object to use static memory by default and to be copied instead of referenced?
For example, I have an object Color with 3 int components r, g and b. I dont want these objects to be in dynamic memory and referenced when passing to functions, I want them immutable and to be copied like an int or a float.
I know I can use a c struct, but I also need the object Color to have methods that gets/sets lightness, hue, saturation, etc. I want my code to be object oriented.
Is there any solution to this?
EDIT: If for example I'm building a 3d game engine, where I'll have classes like Vector2, Vector3, Matrix, Ray, Color, etc: 1) I need them to be mutable. 2) The size of the objects is roughly the same size of a pointer, so why would I be copying pointers when I can copy the object? It would be simpler, more efficient, and I wouldnt need to manage memory, specially on methods that returns colors. And In the case of a game engine, efficiency is critical.
So, if there is no solution to this... Should I use c-structs and use c-function to work on them? Isn't there a better choice?
Thanks.
You can't do this. This isn't how Objective-C works (at least the Apple/GNU version*). It simply isn't designed for that sort of extreme low-level efficiency. Objects are allocated in dynamic memory and their lifetimes are controlled by methods you call on them, and that's just how it works. If you want more low-level efficiency, you can either use plain C structs or C++. But keep in mind that worrying about this is pointless in 99% of circumstances — the epitome of premature optimization. Objective-C programs are generally very competitive with C++ equivalents both in execution speed and memory use despite this minor inefficiency. I wouldn't go for a more difficult solution until profiling had proved it to be necessary.
Also, when you're new to Objective-C, it's easy to psych yourself out over memory management. In a normal Cocoa (Touch) program, you shouldn't need to bother about it too much. Return autoreleased objects from methods, use setters to assign objects you want to keep around.
*Note: There was an old implementation of Objective-C called the Portable Object Compiler that did have this ability, but it's unrelated to and incompatible with the Objective-C used on Macs and iOS devices. Also, the Apple Objective-C runtime includes special support for Blocks to be allocated on the stack, which is why you must copy them (copy reproduces the block in dynamic memory like a normal object) if you want to store them.
What if I need an object to use static memory by default and to be copied instead of referenced?
You don't.
Seriously. You never need an object to use static memory or be allocated on the stack. C++ allows you to do it, but no other object oriented language I know does.
For example, I have an object Color with 3 int components r, g and b. I dont want these objects to be in dynamic memory and referenced when passing to functions, I want them immutable and to be copied like an int or a float.
Why do you not want the objects to be in static memory? What advantage do you think that gives you?
On the other hand it's easy to make Objective-C objects immutable. Just make the instance variables private and don't provide any methods that can change them once the object is initialised. This is exactly how the built in immutable classes work e.g. NSArray, NSString.
One solution that people use sometimes is to use a singleton object (assuming you only need one of the objects for your entire app's lifetime). In that case, you define a class method on the class and have it return an object that it creates once when it is first requested. So you can do something like:
#implementation MyObject
+ (MyObject *)sharedObjectInstance
{
static MyObject *theObject=nil;
if (theObject==nil)
{
theObject = [[MyObject alloc] init];
}
return theObject;
}
#end
Of course the object itself isn't what's being statically allocated, it's the pointer to the object that's statically allocated, but in any case the object will stick around until the application terminates.
There are times when you want to do this because you really only want one globally shared instance of a particular object. However, if that's not your objective, I'm not sure why you'd want to do what you're describing. You can always use the -copy method to create a copy of an object (assuming the object conforms to the NSCopying protocol) to manipulate without touching the original.
EDIT: Based on your comments above it seems you just want to have immutable objects that you can copy and modify the copies. So using -copy is probably the way to go.
I have sort of a simple question. I am writing an Objective-C program with some multithreading. I have a global NSArray, and I add objects into that NSArray from a method that is called in a new thread. If the objects I add into that NSArray are new objects created in that method (local), will that create memory access and/or other issues or will the garbage collector be smart enough to keep those objects around until they have no more references? Also, if I want to an object into that NSArray, will that object be passed by reference or by value?
Can you add objects in NSArray? I guess you mean NSMutableArray.
NSMutableArray is NOT thread safe. So you may need to acquire a lock before trying to modify it. Though this will mostly dependent on how your threads are working on shared data.
NSArray or NSMutableArray will retain the objects that they contains. So after adding you can release the local copy.
The array will store the reference.
Hope it helps. In general multithreading is much more difficult than a single thread app. Please check Threading Programming Guide for the details. It may save you from many hazards.
There should be no problems with the design you're describing. All of your threads share the same memory space, so everything will work just fine. The memory management system will do "the right thing", but I recommend learning the retain/release method - there's nothing better than actually understanding what your program is doing.
Objective-C is pass-by-value only, just like C. That said, objects are only ever passed around by pointers in Objective-C, so you can think of it as always pass-by-reference in that sense.