What are the pros and cons of creating an array (or any other collection using its respective factory method) with
[[NSArray alloc] init]
vs
[NSArray array]
in objective C? It seems like the latter factory method allows us to not worry about memory management, so I was curious if there's any point in ever using alloc + init, though I'm now more interested in all the differences between these two, and why one would choose one over the other.
Prior to ARC there was a critical difference. The alloc/init case returned a retained object, while the array case returned an autoreleased object.
With ARC the difference is less important. Probably the first case is a hair more efficient, but in most scenarios they are interchangeable.
In the first one, you have the ownership of array object & you have to release them.
NSMutableArray* p = [[NSMutableArray alloc] init];
[p release];
& last one you dont need to release as you don't have the ownership of array object.
NSMutableArray* p = [NSMutableArray]; //this is autoreleased
If you call release in this, then it will crash your application.
Related
I have a question regarding memory allocation for Objects in an array. I am looking to create an array of Objects, but at compile time, I have no way of knowing how many objects I will need, and thus don't want to reserve more memory than needed.
What I would like to do is allocate the memory as needed. The way I would like to do this is when the user clicks an "Add" button, the array is increased by one additional object and the needed memory for the new object is allocated.
In my novice understanding of Objective C (I was a professional programmer about 20 years ago, and have only recently begun to write code again) I have come up with the following code segments:
First, I declared my object:
NSObject *myObject[1000]; // a maximum number of objects.
Then, when the user clicks an Add button it runs a method with the allocation code: (note: the variable i starts out at a value of 1 and is increased each time the Add button is clicked)
++i
myObject[i] = [[NSObject alloc] init];
Thus, I'm hoping to only allocate the memory for the objects actually needed, rather than all 1000 array objects immediately.
Am I interpreting this correctly? In other words, am I correct in my interpretation that the number of arrayed elements stated in the declaration is the MAXIMUM possible number of array elements, not how much memory is allocated at that moment? It this is correct, then theoretically, the declaration:
NSObject *myObject[10000];
Wouldn't pull any more memory than the declaration:
NSObject *myObject[5];
Can someone confirm that I'm understanding this process correctly, enlighten me if I've got this mixed up in my mind. :)
Thanks!
Why not use NSMutableArray? You can initWithCapacity or simply allocate with [NSMutableArray array]. It will grow and shrink as you add and remove objects. For example:
NSMutableArray *array = [NSMutableArray array];
NSObject *object = [[NSObject alloc] init];
[array addObject:object]; // array has one object
[array removeObjectAtIndex:0]; // array is back to 0 objects
// remember to relinquish ownership of your objects if you alloc them
// the NSMutable array was autoreleased but the NSObject was not
[object release];
Your understanding is mostly correct. When you do:
NSObject *myObject[1000];
You immediately allocate storage for 1000 pointers to NSObject instances. The NSObject instances themselves are not allocated until you do [[NSObject alloc] init].
However, doing NSObject *myObject[10000] will consume more space than doing NSObject *myObject[5], because 10,000 pointers certainly require more memory to represent than 5 pointers.
Remember that both things consume space, the pointer to the NSObject, and the NSObject instance itself, though in practice the space consumed by an NSObject instance will be significantly larger than the 4 bytes consumed by the pointer that refers to it.
Anyhow, perhaps more importantly, there is a better way to manage dynamic object allocation in Cocoa. Use the built-in NSMutableArray class. Like:
NSMutableArray* objects = [[NSMutableArray alloc] init];
[objects addObject: [[[NSObject alloc] init] autorelease]];
I am new to Objective-C, so this might be a dumb question.
I cannot help but see the similarities between ObjC and Microsoft's COM with respect to memory management (AddRef/Release vs retain/release). In a COM environment, it's more or less imposed on you to always AddRef (retain) an object before returning it to the caller. From what I've seen so far (I'm a third through Cocoa® Programming for Mac® OS X (3rd Edition)), the memory management part is somewhat fuzzy.
Assuming there is no GC, what is the idiomatic way to return an object?
Read Memory Management Programming Guide about autorelease pools.
In Objective-C, by convention, objects should be returned autoreleased (unless the method returning the object has a name that begins with “alloc”, “new”, “copy”, or “mutableCopy”). Autoreleased objects are tracked by Objective-C in a pool and automatically handled, which means you don't need to care about sending a final release to them. This greatly simplifies reference counting compared to COM, and this is why you're not seeing any release calls on returned objects most of the time. In contrast, the same convention specifies that all objects returned by a method whose name begins with alloc, new, copy, or mutableCopy, are the responsibility of the method caller. You have to manually call release on these objects or your program will have memory leaks.
Cocoa goes around the limitations of AddRef/Release in COM by introducing a third sibling; autorelease.
retain - I need this, make it stick around.
release - I don't need this anymore, you may remove it immediately.
autorelease - I don't need this, but let it stay around a few seconds in case someone else wants to pick it up first.
This tiny addition allow most return values to be handles as-if we had garbage collection. If you are not interested in keeping the return value around, just do nothing extra.
In order to get this to work there is a convention (a convention good enough to let the compiler do the memory stuff automatically for you with upcoming ARC):
Method names beginning with these must return retained instances:
alloc
copy
new
retain
All other must return autoreleased instances.
Three example implementation for how this can be applied in practice:
-(NSString*)newHelloWorldString {
NSString* s = [NSString stringWithString:#"Hello world"];
// Apply retain because s in now autoreleased
return [s retain];
}
-(NSString*)helloWorldString {
NSString* s = [[NSString alloc] initWithString:#"Hello world"];
// Apply autorelease because s is now retained.
return [s autorelease];
}
-(NSString*)fullName {
// No memory management needed, everything is autoreleased and good.
NSString* fn = [self firstName];
NSString* ln = [self lastName];
NSString* s = [NSString stringWithFormat:#"%# %#", fn, ln];
return s;
}
Generally something like
return [object autorelease];
and you can retain on the other end.
If you are planning to deploy on Lion/iOS5 or are using the latest SDK then also check out ARC.
Essentially i would recommend making the class that receives it retain it. i.e class stackoverflow receives object answer.
i.e
-(void) setAnswer:(Answer*) _answer{
self.answer = _answer; // If the answer is created from a returned message.
[_answer release];
}
edit: I think I might have put up the wrong stuff up there now that i am looking at it the 2nd time . Meant something along the lines:
Answer *_answer = [stackoverflow createAnswer];
self.answer = _answer;
[_answer release];
If you return an object , it is up to the owner to retain it , i would avoid autoreleases wherever possible because once the nspool kicks in, those objects are gone and if they are still used, it will cause problems.
i.e Answer *answer = [stackoverflow getAnswer] and if answer was created in the getanswer method then whomever is retrieving it is responsible in releasing it.
Makes sense?
Can you please explain me exact difference between these two lines?
NSArray *foo = [NSArray arrayWithObjects:#"hai",#"how",#"are",#"you",nil];
NSArray *bar = [[NSArray alloc] initWithObjects:#"hai",#"how",#"are",#"you",nil];
arrayWithObjects is "convenience constructor".
It will do:
return [[[NSArray alloc] initWithObjects:#"hai",#"how",#"are",#"you",nil] autorelease]
for you.
It is just a convenience method to get an autoreleased object while improving the readability of the statement. Keep in mind that the fact that the object is autoreleased is a simple convention of the language (not a rule, so you could do differently, but I would not suggest that).
arrayWithObject returns an autoreleased array so you do not have to worry about releasing it when you don't need it anymore (but if you store it in an instance variable, you should retain it to prevent the autorelease pool from freeing it). initWithObject returns an array with a retain count of 1, i.e. you own the array and you must release it at some point to prevent memory leaks.
You might want to read this guide for more clarification.
You own the second array but not the first.
Sorry for the newbie question, but I need a NSMutableArray with some NSNumber inside, created dynamically in a for cycle. My code looks like this:
for (...){
NSNumber *temp_number = [[NSNumber alloc] initWithInteger:someNSInteger];
[target_array addObject:[temp_number copy]];
[temp_number release];
}
Is this a correct way to do it? Does it leak?
Thanks! Miguel
Yep, that leaks. You want:
NSNumber *temp_number = [[NSNumber alloc] initWithInteger:someNSInteger];
[target_array addObject:temp_number];
[temp_number release];
So, no copy. The logic is that because you use alloc, you end up owning temp_number. You then add it to the array and the array does whatever it needs to. You've used temp_number for its intended purpose, so you no longer want to own it and release it.
If you were to take a copy, that would create another instance of NSNumber, which you also own, and therefore which you should also release when you're finished with.
In practice, the array (if it's allocated and exists, rather than being nil), will retain the object for itself, but that's an implementation detail specific to that class and not something you should depend upon or even be particularly interested in beyond the contract that says that the objects you add can later be found in the array.
In other languages I could create a class then use this to create an array of objects in that class eg class price which is used in a performance class to define a price[] prices;
in objective C i cant get this to work, how do you do it?
The price class is an inherit of NSObject, can I use NSMutableArray?
If you have a class Price, and it inherits from NSObject, then you can have an array of them stored in an NSArray or NSMutableArray. You could also store them in a C array, or an STL vector, although the memorymanagement sematics may be difficult in those cases.
In the case of an NSArray/NSMutableArray, the array takes an ownership reference on the object, so you can release it after adding it to the array, and it will remain in memory until it is removed from the array (and all other locations).
Code might look like:
NSMutableArray* a = [NSMutableArray array];
[a addObject:[Price price]];
// and/or
[a addObject:[[[Price alloc] init] autorelease];
// and/or
Price* p = [[Price alloc] init];
[a addObject:p];
[p release];
NSLog( #"The array is %#", a );
// Remember at this point you do not "own" a, retain it if you want to keep it, or use [NSMutableArray new] above
When a is released, all the Price objects it contains will be released (and potentially deallocated).
Yes, NSMutableArray is what you would want to use.
To answer your last question first: if you are storing instances of Objective-C object (which, as you say, inherit from NSObject) then yes, use NSMutableArray. However, this won't work for primitive types (like int, BOOL, char, char*, etc.).
Objective-C uses the C way of declaring arrays with one caveat: you can't allocate memory on the stack (which is what that does in C), only on the heap. That means you have to use malloc (prefer NSAllocateCollectable() on Leopard or later) and free to manage the memory. Also, you declare the array as a pointer to an array or pointers. Something like this: (Note: pulled from thin air, untested.)
Price **prices = malloc(numberOfEntries * sizeof(Price*));
...
free(prices);
Using an NSMutableArray is generally much easier than managing your own arrays. Just be aware of the memory management rules: collections call -retain on an object when it is inserted, and -release on it when it is removed (or on all objects if the collection is deallocated).