NSMutableArray initialization methods - objective-c

Is there a difference between [NSMutableArray array] and [[NSMutableArray alloc] init] ?

[[NSMutableArray alloc] init] returns a mutable array that you own (and therefore have to explicitly relinquish ownership using release when you no longer need it) and [NSMutableArray array] returns a mutable array that you don't own.
According to the Memory Management Rules, any method with the word alloc, new, or create in the name, implies that you own the object returned from that method.

Related

What is the difference between these two lines of Objective-C code?

NSArray *emptyArray = [NSArray array];
NSArray *emptyArray = [[NSArray alloc] init];
Both of them seem to create empty array. So what's the difference?
They do a similar thing, but not quite exactly the same thing.
[NSArray array] creates an autoreleased array
[[NSArray alloc] init] creates an array with a retain count of 1 making emptyArray its owner.
With ARC, you won't notice much of a difference, but with manual memory management you will. If you're using ARC you can probably safely use either, but I'd recommend you stick to one format (I personally prefer to use alloc/init).
Here is an excerpt of NSArray.m from GNUstep which follows closely to Apple's Cocoa (formerly NeXT's OpenStep):
/**
* Returns an empty autoreleased array.
*/
+ (id) array
{
id o;
o = [self allocWithZone: NSDefaultMallocZone()];
o = [o initWithObjects: (id*)0 count: 0];
return AUTORELEASE(o);
}
The difference is how the memory is managed:
NSArray *emptyArray = [NSArray array];
In this case emptyArray is pointing to an autoreleased array object, meaning that you don't own the object. But also this means that, if you're NOT using ARC, you can't use this object after the current run loop, unless you increment it's retain count, because it could be destroyed.
NSArray *emptyArray = [[NSArray alloc] init];
In this case you get an array with a retain count of +1. This means that you're responsible for deallocating the memory when you're done using it.
This difference is specially important if you're not using ARC.
NSArray *emptyArray = [NSArray array];
is similar to
NSArray *emptyArray = [[[NSArray alloc] init] autorelease];
This means, [NSArray array] returns auto released object. So you do not need to release object created using [NSArray array].
But you are responsible to release object created using [[NSArray alloc] init].
Basically new instances returned from class methods return autoreleased instances which indeed means IOS holds ownership of it and thus no need to worry on releasing it.
NSArray *arr=[NSArray array]; is same as NSArray *emptyArray=[[[NSArray alloc] init] autorelease];
When using [[NSArray alloc] init] if you are using MRC then you are responsible to release while it is taken care automatically for you in ARC.
Hence irrespective of ARC or MRC it is always better to use [NSArray array].

Can I release an object created outside a block that uses it before the block is run?

Can myArray be safely released before the block?
NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:#"a"];
[myArray addObject:#"b"];
// releasing here causes an invalid object to be used inside the block?
[myArray release];
CCCallBlock *block = [CCCallBlock actionWithBlock:^{
// print myArray contents to console
}];
[myNode runAction:block];
No, you cannot release the array before the block, because the objects inside the array and the array itself will not be usable after the call of release, before your block gets a chance to retain it.
You can make your array autoreleased, in which case the release would happen after the function exits.
NSMutableArray *myArray = [NSMutableArray array];
[myArray addObject:#"a"];
[myArray addObject:#"b"];
CCCallBlock *block = [CCCallBlock actionWithBlock:^{
// print myArray contents to console
}];
[myNode runAction:block];
To add to what the other people said, without autorelease, you can release the array after the block is created, if you no longer use the array after that.
NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:#"a"];
[myArray addObject:#"b"];
CCCallBlock *block = [CCCallBlock actionWithBlock:^{
// print myArray contents to console
}];
[myArray release];
[myNode runAction:block];
The block retains the captured objects (the array) when it is created.
No. You would retain a dangling pointer in the block.

Memory management while copying objects

I know that my question has already been discussed on StackOverflow but i found the answer not complete for my needs. So the question is:
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
secondArray = [firstArray mutableCopy];
what is retain count for the secondArray now? 2 or 1? Should i release it twice or just once?
Does copy or mutableCopy increases retain count of the COPYING (secondArray in this event) object?
You should never care about the absolute retain count. Only that you're "balanced", that means for every alloc, new*, copy, mutableCopy and retain you need a corresponding release or autorelease (when not using ARC, that is).
If you apply this rule to each line you can see that your second line has an alloc, but there's no release. In fact, it's absolutely useless to allocate an instance here since you're not interested in it anyway. So it should simply read:
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [firstArray mutableCopy];
// There is no third line.
But let's discuss your original code and see what happened:
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
// secondArray points to a new instance of type NSMutableArray
secondArray = [firstArray mutableCopy];
// You have copied another array (created a new NSMutableArray
// instance) and have overwritten the pointer to the old array.
// This means that the instance allocated in line 2 is still there
// (was not released) but you don't have a pointer to it any more.
// The array from line 2 has been leaked.
In Objective-C, we often speak of ownership: there are very few methods that make you the "owner" of an object. These are:
alloc
new*, as in newFoo
copy and mutableCopy
retain
If you call these, you get an object for which you are responsible. And that means you need to call a corresponding number of release and/or autorelease on these objects. For example, you're fine if you do [[obj retain] retain]; and then [[obj autorelease] release];
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
secondArray = [firstArray mutableCopy];
What is happening is that you've created a memory leak. You just lost the reference assigned to secondArray when you overwrote it with the mutableCopy of firstArray with this line.
secondArray = [firstArray mutableCopy];
If you then release secondArray twice, the program will crash because you're then overreleasing the mutable array assigned by
secondArray = [firstArray mutableCopy];
What you need to do is to make sure you're not overwriting retained references by mistake, and balance retains with releases.

problems during object release

I have some problems during when and which object to be release
You can say my knowledge towards this is less
i have following conditions please suggest me the answer accordingly
situation-1
NSMutableString *str=[[NSMutableString alloc]initWithFormat:#"Hello World!"];
NSMutableArray *array=[[NSMutableArray alloc]init];
[array addObject:str];
Now when i tried to release str then usage of array affected in future...and Vice Versa
Tell me can i release both?
situation-2
NSMutableString *str=[[NSMutableString alloc]init];
str=#"Hello World !";
str=[self getData]; //calling a method which returns a string
[str release];
I think i am creating a memory leak here(how to solve it?)
please clear these situations
in the first situation, you'll need to call [str release]; after adding it to the array, like this:
NSMutableString *str = [[NSMutableString alloc] initWithString:#"Hello World!"];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:str];
[str release];
This way, array holds the only retain call on the string. Once you release array later, you won't have any memory leak issues.
I'm a little confused about the second situation. str here is a pointer. You seem to be assigning three different objects to to same pointer:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
str=#"Hello World !"; //second object
str=[self getData]; //third object
by the time you call [str release], you've created a memory leak because you've lost the first mutable string. The second time you called str =, you lost any way to access that first NSMutableString.
Assuming that you're looking to concatenate all of these (since you chose NSMutableString), you might try this:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
[str appendString:#"Hello World!"];
[str appendString:[self getData]];
[str release];
If the [self getData] method returns an autoreleased string, you'll be fine. If getData returns a retained string (if you used alloc and init), you'll need to assign it to an intermediate pointer and release it after adding it to str.
What is the need of creating the NSMutableString You can directly use NSString for this purpose

How do I convert NSMutableArray to NSArray?

How do I convert NSMutableArray to NSArray in objective-c?
NSArray *array = [mutableArray copy];
Copy makes immutable copies. This is quite useful because Apple can make various optimizations. For example sending copy to a immutable array only retains the object and returns self.
If you don't use garbage collection or ARC remember that -copy retains the object.
An NSMutableArray is a subclass of NSArray so you won't always need to convert but if you want to make sure that the array can't be modified you can create a NSArray either of these ways depending on whether you want it autoreleased or not:
/* Not autoreleased */
NSArray *array = [[NSArray alloc] initWithArray:mutableArray];
/* Autoreleased array */
NSArray *array = [NSArray arrayWithArray:mutableArray];
EDIT: The solution provided by Georg Schölly is a better way of doing it and a lot cleaner, especially now that we have ARC and don't even have to call autorelease.
I like both of the 2 main solutions:
NSArray *array = [NSArray arrayWithArray:mutableArray];
Or
NSArray *array = [mutableArray copy];
The primary difference I see in them is how they behave when mutableArray is nil:
NSMutableArray *mutableArray = nil;
NSArray *array = [NSArray arrayWithArray:mutableArray];
// array == #[] (empty array)
NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil
you try this code---
NSMutableArray *myMutableArray = [myArray mutableCopy];
and
NSArray *myArray = [myMutableArray copy];
Objective-C
Below is way to convert NSMutableArray to NSArray:
//oldArray is having NSMutableArray data-type.
//Using Init with Array method.
NSArray *newArray1 = [[NSArray alloc]initWithArray:oldArray];
//Make copy of array
NSArray *newArray2 = [oldArray copy];
//Make mutablecopy of array
NSArray *newArray3 = [oldArray mutableCopy];
//Directly stored NSMutableArray to NSArray.
NSArray *newArray4 = oldArray;
Swift
In Swift 3.0 there is new data type Array. Declare Array using let keyword then it would become NSArray And if declare using var keyword then it's become NSMutableArray.
Sample code:
let newArray = oldArray as Array
In objective-c :
NSArray *myArray = [myMutableArray copy];
In swift :
var arr = myMutableArray as NSArray
NSArray *array = mutableArray;
This [mutableArray copy] antipattern is all over sample code. Stop doing so for throwaway mutable arrays that are transient and get deallocated at the end of the current scope.
There is no way the runtime could optimize out the wasteful copying of a mutable array that is just about to go out of scope, decrefed to 0 and deallocated for good.
If you're constructing an array via mutability and then want to return an immutable version, you can simply return the mutable array as an "NSArray" via inheritance.
- (NSArray *)arrayOfStrings {
NSMutableArray *mutableArray = [NSMutableArray array];
mutableArray[0] = #"foo";
mutableArray[1] = #"bar";
return mutableArray;
}
If you "trust" the caller to treat the (technically still mutable) return object as an immutable NSArray, this is a cheaper option than [mutableArray copy].
Apple concurs:
To determine whether it can change a received object, the receiver of a message must rely on the formal type of the return value. If it receives, for example, an array object typed as immutable, it should not attempt to mutate it. It is not an acceptable programming practice to determine if an object is mutable based on its class membership.
The above practice is discussed in more detail here:
Best Practice: Return mutableArray.copy or mutableArray if return type is NSArray
i was search for the answer in swift 3 and this question was showed as first result in search and i get inspired the answer from it
so here is the swift 3 code
let array: [String] = nsMutableArrayObject.copy() as! [String]