Is there a difference between the initializations [NSArray new] and [NSArray array]?
array seems to be part of the implementation of NSArray while new belongs to NSObject.
new = alloc + init
This method is a combination of alloc and init. Like alloc, it
initializes the isa instance variable of the new object so it points
to the class data structure. It then invokes the init method to
complete the initialization process.
NSObject Class Reference
+new is implemented quite literally as:
+ (id) new
{
return [[self alloc] init];
}
and new doesn't support custom initializers (like initWithObjects), so alloc + init is more explicit than new
So the question now is about:
[NSArray array] vs [[NSArray alloc] init]
The main difference between these is if you're not using ARC
(Automatic Reference Counting). The first one returns a retained and
autoreleased object. The second one returns an object that is only
retained. So in the first case, you would want to retain it if you
wanted to keep it around for longer than the current run loop. In the
second case, you would want to release or autorelease it if you didn't
want to keep it around.
Now that we have ARC, this changes things. Basically, in ARC code, it
doesn't matter which of these you use.
But keep in mind that [NSArray array] returns an empty immutable array, so using array with NSMutableArray makes more sense
For more information:
alloc, init, and new in Objective-C
Use of alloc init instead of new
Difference between [NSMutableArray array] vs [[NSMutableArray alloc] init]
Related
Here is code I am referring to.
// Person.h
#interface Person : NSObject {
NSString *firstName;
NSString *lastName;
}
#end
// Person.m
#implementation Person
- (id)init {
if (![super init]) return nil;
firstName = #"John";
lastName = #"Doe";
}
#end
// MyClass.m
#implementation MyClass
.....
- (NSArray *)getPeople {
NSMutableArray *array = [[NSMutableArray alloc] init];
int i;
for (i = 0; i < 10; i++) {
Person *p = [[Person alloc] init];
[array addObject:p];
}
return array;
}
.....
#end
Now, I know there is no memory-management going on in this sample code. What would be required?
In the getPeople loop, I am alloc'ing a Person (retainCount 1), then adding it to array. The retain count is now 2, right? If it is two, should I be [p release]'ing after adding it to the array, bringing the retainCount back down to 1?
Am I right in that it is the caller's responsibility to release the array returned by the method? (Which would also free the memory of the Person's, and their instance variables, assuming their counts are at 1).
I have read Apple's memory management document, but I guess what I am most unclear about, is what increases an objects retain count? I think I grasp the idea of who's responsibility it is to release, though. This is the fundamental rule, according to Apple:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
bobDevil's sentence "only worry about the retain counts you add to the item explicitly" made it click for me. After reading the Ownership policy at Apple, essentially, the object/method that created the new object, is the one responsible for releasing /it's/ interest in it. Is this correct?
Now, let's say I a method, that receives an object, and assigns it to a instance variable. I need to retain the received object correct, as I still have an interest in it?
If any of this is incorrect, let me know.
You are correct that the retain count is 2 after adding it to an array. However, you should only worry about the retain counts you add to the item explicitly.
Retaining an object is a contract that says "I'm not done with you, don't go away." A basic rule of thumb (there are exceptions, but they are usually documented) is that you own the object when you alloc an object, or create a copy. This means you're given the object with a retain count of 1(not autoreleased). In those two cases, you should release it when you are done. Additionally, if you ever explicitly retain an object, you must release it.
So, to be specific to your example, when you create the Person, you have one retain count on it. You add it to an array (which does whatever with it, you don't care) and then you're done with the Person, so you release it:
Person *p = [[Person alloc] init]; //retain 1, for you
[array addObject:p]; //array deals with p however it wants
[p release]; //you're done, so release it
Also, as I said above, you only own the object during alloc or copy generally, so to be consistent with that on the other side of things, you should return the array autoreleased, so that the caller of the getPeople method does not own it.
return [array autorelease];
Edit:
Correct, if you create it, you must release it. If you invest interest in it (through retain) you must release it.
Retain counts are increased when you call alloc specifically, so you'll need to release that explicitly.
factory methods usually give you an autoreleased object (such as [NSMutableArray array] -- you would have to specifically retain this to keep it around for any length of time.).
As far as NSArray and NSMutableArray addObject:, someone else will have to comment. I believe that you treat a classes as black boxes in terms of how they handle their own memory management as a design pattern, so you would never explicitly release something that you have passed into NSArray. When it gets destroyed, its supposed to handle decrementing the retain count itself.
You can also get a somewhat implicit retain if you declare your ivars as properties like #property (retain) suchAndSuchIvar, and use #synthesize in your implementation. Synthesize basically creates setters and getters for you, and if you call out (retain) specifically, the setter is going to retain the object passed in to it. Its not always immediately obvious, because the setters can be structured like this:
Person fart = [[Person alloc] init];
fart.firstName = #"Josh"; // this is actually a setter, not accessing the ivar
// equivalent to [fart setFirstName: #"Josh"], such that
// retainCount++
Edit:
And as far as the memory management, as soon as you add the object to the array, you're done with it... so:
for (i = 0; i < 10; i++) {
Person *p = [[Person alloc] init];
[array addObject:p];
[p release];
}
Josh
You should generally /not/ be worried about the retain count. That's internally implemented. You should only care about whether you want to "own" an object by retaining it. In the code above, the array should own the object, not you (outside of the loop you don't even have reference to it except through the array). Because you own [[Person alloc] init], you then have to release it.
Thus
Person *p = [[Person alloc] init];
[array addObject:p];
[p release];
Also, the caller of "getPeople" should not own the array. This is the convention. You should autorelease it first.
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
You'll want to read Apple's documentation on memory management: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
I'm trying to understand this from a memory management point of view: In one class, I'm making a helper method that will create an NSDictionary object for me.
+(NSDictionary*) getTheDictionary{
return [[[NSDictionary alloc] initWithObjectsAndKeys:
#"value", #"key", nil] autorelease];
}
From another class, I use the method.
NSDictionary* theDictionary = [HelperClass getTheDictionary];
Is it enough to just have "autorelease" in the return statement? Do I also need an autorelease on theDictionary?
getTheDictionary returns an autoreleased object, which means that the object is
valid in the calling method, but not owned by the caller. Therefore the calling method
must not release or autorelease that object.
It will be released when the current autorelease pool ends, e.g. when program control
returns to the main event loop.
NSMutableArray * arrayTest;
-(void) setContent
{
//must I call [array removeAllObjects]; ?
arrayTest = [[NSMutableArray alloc] init]
[arrayTest addObject:#"str"];
...//add many objects
}
I call this function at different code snippet. do I need to removeAllObjects of arrayTest before , then alloc memory for arrayTest every time ? I use ARC .
I don't want my app memory to increase every time I call this function.
No, what you have is fine. You don't need to call removeAllObjects under ARC or non-ARC.
When the old array is deallocated, it will take care of releasing all of the objects in the old array.
Check if arrayTest exists before alloc'ing memory. If you don't you'll have a new array every time the method is called (assuming you want to keep the array and it's content around for a while). Or even better.. move the alloc into the init of the class.
-(void) setContent
{
if(!arrayTest){
arrayTest = [[NSMutableArray alloc] init];
}
[arrayTest addObject:#"str"];
...//add many objects
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
alloc, init, and new in Objective-C
I am a little confused about [Class new] and [[Class alloc] init]. I have defined an object content using [Class new] and [[Class alloc] init].
(1). NSMutableArray *content = [NSMutableArray new];
(2). NSMutableArray *content = [[NSMutableArray alloc] init];
My question is about the differences between [Class new] and [[Class alloc] init]. For me, (1) and (2) are similar. If (1) and (2) are similar, then why do we use [[Class alloc] init] most of the time, compared to [Class new]? I think that there must be some difference.
Kindly explain the differences, pros & cons of both?
Alloc: Class method of NSObject. Returns a new instance of the receiving class.
Init: Instance method of NSObject. Implemented by subclasses to initialize a new object (the receiver) immediately after memory for it has been allocated.
New: Class method of NSObject. Allocates a new instance of the receiving class, sends it an init message, and returns the initialized object.
Release: Instance method of NSObject delegate. Decrements the receiver’s reference count.
Autorelease: Instance method of NSObject delegate. Adds the receiver to the current autorelease pool.
Retain: Instance method of NSObject delegate. Increments the receiver’s reference count.
Copy: Instance method of NSObject delegate. Returns a new instance that’s a copy of the receiver.
So to conclude we can say that
alloc goes with init
new = alloc + init
The +new method is simply shorthand for +alloc and -init. The ownership semantics are identical. The only benefit to using +new is that it is more concise. If you need to provide arguments to the class's initialiser, you will have to use the +alloc and -initWith... methods instead.
Here: alloc, init, and new in Objective-C
Basically it's a question of modern versus traditional. The most direct advantage of init over new is that there are many custom init methods.
I'm trying to switch views in my app using this chunk of code:
self->variable1 = [[NSNumber alloc] initWithInt:0];
self->variable2 = [[NSMutableArray arrayWithCapacity:1];
self->variable3 = [[NSMutableArray arrayWithCapacity:1];
[self presentModalViewController:titleScreen animated:YES];
If I comment out all of the allocated variable lines, the code works fine. If it leave just 1 line in the code crashes with the "EXC_BAD_ACCESS" error. Why is this happening? The variables aren't being used at all, just declared for later use. I'm not getting any compile errors on the lines either. What am I doing wrong?
UPDATE:
Thank you everyone for the help. I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem. After a long time of fiddling I fixed it. I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
and it worked! Can someone explain why this worked and the first line didn't?
Update:
Thank you Peter Hosey for showing me my evil ways. This time I'm pretty sure it's fixed. I was storing my variable Releases in
-(void)release
I didn't realize xCode will release when it needs to. I moved all the variable releases to
-(void)Destroy
so I can release everything on MY command. Now the code works. Thanks again!
I suggest that you declare variable1, variable2, and variable3 as properties, not instance variables. Then, use self.variable1, self.variable2, and self.variable3 to access them.
The dot syntax (self.variable1, etc.) uses the memory management policy you declared on each property; the arrow syntax (self->variable1, etc.) will access the variables directly. The crash is because you created two arrays in away that doesn't leave you owning them, and then did not assign the arrays to a property that would retain them.
You may also want to upgrade your project to use ARC. Then there is no memory-management difference; assigning to the instance variables rather than the properties will not cause the object to be prematurely released, because ARC considers instance variables to be ownerships by default. You may still want to switch to using properties after you switch to ARC, but not to prevent a crash.
In response to your edit:
I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem.
Then something else was wrong.
You never did say much about the problem itself. You said you got an EXC_BAD_ACCESS, but not what statement triggered the crash or on what grounds you blamed it on the code you showed.
I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
That's the correct code, though. That's what you should be using.
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
Noooo! That code is wrong, wrong, wrong, on multiple levels.
init methods (including initWithWhatever: methods) are not guaranteed to return the same object you sent the message to. NSNumber's initWithInt: very probably doesn't.
That object creates an uninitialized NSNumber object and assigns that to the property. Then it sends initWithInt: to that object, which will return an initialized object, which can be and very probably will be a different object. Now you are holding an uninitialized object (which you will try to use later) and have dropped the initialized object on the floor.
Never, ever, ever send alloc and init(With…) in separate expressions. Always send them in the same expression. No exceptions. Otherwise, you risk holding the uninitialized object rather than the initialized object. In your case (with NSNumbers), that is almost certainly what will happen.
What you should be doing is declaring and synthesizing a strong property that owns the NSNumber object, and creating the NSNumber object in a single statement: either [[NSNumber alloc] initWithInt:] or [NSNumber numberWithInt:]. If you're not using ARC, you'll want the latter, since the property will retain the object. If you are using ARC, they're effectively equivalent.
And if you get a crash with that code, then something else is wrong, so please tell us—either in this question or in a new question—about the crash so we can help you find the true cause of it.
variable2 and variable3 are being autoreleased before you actually access them (presumably) later after presenting the modal view.
At the very least change the lines to:
self->variable2 = [[NSMutableArray arrayWithCapacity:1] retain];
self->variable3 = [[NSMutableArray arrayWithCapacity:1] retain];
or
self->variable2 = [[NSMutableArray alloc] initWithCapacity:1];
self->variable3 = [[NSMutableArray alloc] initWithCapacity:1];
variable1 should be fine.
Best would be to use #property and #synthesize so you can use dot notation:
.h
#interface MyClass : SuperClass
#property (nonatomic,retain) NSMutableArray *variable2;
#property (nonatomic,retain) NSMutableArray *variable3;
#end
.m
#implementation MyClass
#synthesize variable2,varible3;
- (void)foo {
self.variable2 = [NSMutableArray arrayWithCapacity:1];
self.variable3 = [NSMutableArray arrayWithCapacity:1];
}
#end
By default, all instance variables in objective-c have protected scope. So unless you have explicitly declared them public in your interface file as:
#interface MYClass {
#public
NSNumber *variable1;
NSMutableArray *variable2;
NSMutableArray *variable3;
}
//...
#end
then they will not be accessible using the struct dereferencing operator. This is likely the cause of those EXC_BAD_ACCESS errors.