NSArray : release its objects, but keep a pointer to it - objective-c

I declare an NSArray in my code then building the array from another array. I process my NSArray and when I'm finished, I would like to release the objects, but I'm reusing this pointer to NSAarray again later to do the same process (creating the array from another array, process then releasing).. So I need to keep the pointer.
What should I do ?
Here is roughly what I want to do, the buildArray is creating and returning an autoreleased NSArray :
NSArray *myArray;
for (int i = 0, i < 10, i++){
myArray = [NSArray arrayWithArray:[self buildArray]];
// Here I process myArray
...
myArray = nil; // is my guess
}
I need to keep a pointer to my NSArray, in order to reuse later in the loop, but what is happening to the objects created with [self buildArray]? What is the best to do in order not to keep unused object and arrays ?
Or maybe the best solution is simply to removeAllObject of the array..?
Thank you!

You can't reuse an NSArray since it's immutable. You can use an NSMutableArray (which supports -removeAllObjects) though.
If are you need is to keep the pointer, but doesn't need it constant within the loops, you could just use
loop {
NSArray* myArray = [self buildArray];
...
// myArray = nil; // optional.
}

Don't do it like that. Instead, do:
for (int i = 0, i < 10, i++){
NSArray *myArray = [self buildArray]; //buildArray should return an autoreleased object
//Process array
//myArray goes out of scope and is autoreleased later, releasing all of its objects
}

Related

correct way to allocate the NSMutableArray

I wanted to know which is the right way to allocate an NSMutableArray.
NSMutableArray *a;
Where a is a class level variable.
First method is:
self.a = [NSMutableArray alloc] init];
Second method is:
a = [NSMutableArray alloc] init];
Which method is better? Can anyone please help me out in this?
If a is a class variable, then correct way to allocate NSMutableArray will be creating a temporary array and assigning it to class variable, followed by releasing the temporary variable.
You can do this way:
NSMutableArray *temp = [[NSMutableArray alloc]init];
self.a = temp;
[temp release];
It depends on the property type. (Though it's in most cases a retain)
You should either use a temp value or create it in one string and send an autorelease message:
self.a = [[NSMutableArray alloc] init] autorelease];
You must send an autorelease becuase a property increases retain count by one. This is the same as doing:
[self setA:array];//where array - is newly created array
Where:
- (void)setA:(NSMutableArray *)array {
if (array != a) {
[a release];
a = [array retain];//here you increased a retain count by 1
}
}
You can also use an autorelease method of creation:
self.a = [NSMutableArray array];
There are several ways. But below way is good enough per me whether you are working with ARC/Non-ARC. Just make sure you have created property.
self.a = [NSMutableArray array];//It will return autorelease object.
The difference between the methods:
1) When you use self.a ,
You use the setter & getter methods created in the #synthesize.
2) When you use just a,
You bypass the accessor methods and directly modify the instance variable. (a in here).
There are two ways to look at it.
Many programmers say that you should never call the accessors from within the implementation of the object as this adds unnecessary overhead.
Some others say that you should always use the accessors, and never access the instance variable directly.
It is generally safe to use an object directly, if you are reading its value only. If you are modifying the object, you should use the accessors in order to make sure that any other objects observing that property are properly notified.
The latest objective C syntax allows you to create mutable and non-mutable arrays very quickly.
The following two examples demonstrate this:
NSArray *objectsToAdd = [#"Ted", #"Ned" , #"Sed"];
NSMutableArray *objectsToAdd = [ #[#"Ted", #"Ned" , #"Sed"] mutableCopy ];
NSMutableArray *a = [[NSMutableArray alloc] init];

Creating local objects, prefrence or simply better?

Is it better to create a local object for later use like
NSDictionary *dic = [NSDictionary Dictionary];
or
NSDictionary * dic = nil;
Is it preference thing or is one better then the other?
it's not like 'the one is better', it's like 'the other is bad'.
If you're going to assign a new object to it later, initialize it to nil, else (you leak memory by losing the reference to the first object created by error.) - EDIT: no, you're not leaking memory (either because of the autorelease or the automatic reference counting, but anyway, that's an extra unneeded method call.) That is bad.
If it's a mutable collection, create it before you use it, else it will continue being nil and ignoring essentially all messages sent to it, which is also bad.
Conclusion: it's not a matter of preference - you must think logically and choose whichever is suited for the specific purpose you are using it for.
If you will use that object later, then you should instantiate it with the first option. If you will have to create an object in some if-else block where you will be reinitializing it with some custom values, then the second option is the way to go.
For example the first option:
NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 5; i++) {
[arr addObject:#"string"];
}
or
NSDictionary *dictionary = nil;
BOOL flag;
if (flag) {
dictionary = [NSDictionary dictionaryWithObject:#"string" forKey:#"myKey"];
}
else {
NSArray *objects;
NSArray *keys;
dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
}

Objective-C method returns NSDictionary instead of NSMutableDictionary. Why?

I am using the included method to return a pointer to a NSMutableDictionary, that is contained in an NSArray. However, the NSMutableArray (theOne) is being created as a non-mutuable NSDictionary. This is a problem because I want to modify the dictionary after retrieving it with this method.
- (NSMutableDictionary*)getMatFromBoutKey:(NSString*) boutKey
{
/*
* Returns the mat object with the provided boutKey.
* Returns nil if no mat has that boutKey.
*/
NSUInteger idx = [[event objectForKey:#"mats"] indexOfObjectPassingTest:
^ BOOL (NSMutableDictionary* obj, NSUInteger idx, BOOL *stop)
{
return [[obj objectForKey:#"boutKey"] isEqualToString:boutKey];
}];
if (idx == NSNotFound)
return nil;
else {
NSMutableDictionary* theOne = [[event objectForKey:#"mats"] objectAtIndex: idx];
return theOne;
}
}
Here's an image of the debugger stopped on a breakpoint right after the theOne is first referenced.
Why isn't theOne mutable? How can I return a pointer to the NSMutableDictionary so that I can modify it after I get the value returned to me?
Thanks!
I'm going to assume that you have a dictionary of arrays. Then that array contains a bunch of regular dictionaries. So when you pull it out of the array it is still a regular dictionary regardless of what you assign it to.
For instance, take the following code for example
NSDictionary *dict = [[NSDictionary alloc] init];
NSMutableDictionary *mutDict = dict;
mutDict will contain a regular dictionary because it has not properly been casted to a mutable dictionary.
either make sure when you create the array that is at [event objectForKey:#"mats"] that you put NSMutable dictionaries inside of it OR
use
NSMutableDictionary* theOne = [[[event objectForKey:#"mats"] objectAtIndex: idx] mutableCopy];
When taking the data out
In general, I think it's better practice to work with immutable objects when mutability isn't strictly necessary. Mutable objects use more memory, and of course have the potential of being accidentally changed. Maybe in the block are being changed to the enumerator(I'm not sure, but it is possible. For faster indexing). If you want to change a mutable object is via mutableCopy. or using a other method.
Is it inserted as mutable elsewhere in the code? If so it should return as mutable, if not you can send it the mutableCopy message to get a mutable copy (that has a reference count of 1, so be sure to release it when necessary).

What is the correct way of returning a NSArray of objects in Objective-C?

I have a method that needs to return an array of objects. The way it does that now is:
Create a NSMutableArray*
Each object, following some computation, is alloc-d and init-ed
Each object, after initialization, is added to the array with addObject
The array is returned
Is autoreleasing the array the right thing to do? What about the objects inside the array? When should these be released?
Yes, setting the array to autorelease before you return it is a reasonable thing to do. Also, if you are calling alloc and init on the things that you put into the array, you should call release (or autorelease) on each one after you add it to the array. Your objects will still be retained as long as they are in the array. Removing them from the array (or releasing the array) will cause them to be released.
Your method should set the array to autorelease and then the caller should retain the returned array. So the method is no longer responsible for the array, the caller is.
The objects in the array will be retained by NSMutableArray, so you should set them to autorelease so they don't leak.
- (NSMutableArray*) calleeMethod
{
// this method is retaining the array temporarily
// someone else is responsible for retaining it
NSMutableArray * newArray = [[[NSMutableArray alloc] init] autorelease];
// add some objects
for (int i = 0; i < 10; i++)
{
// autorelease these objects because newArray will retain each item and
// is responsible for the items
FooObject * newFooObject = [[[FooObject alloc] initWithNumber:i] autorelease];
[newArray addObject:newFooObject];
}
return newArray;
}
- (void) callerMethod
{
// retain the returned array, because we own it
mNewArray = [[self calleeMethod] retain];
// do stuff
// make sure you explicitly release mNewArray later (probably in the dealloc)
}

Terminology question regarding looping thru an NSArray in Objective-C

When you have an NSArray and you want to evaluate and change the elements, you can't change the array from inside the loop. So, you create a mutable copy that can be changed.
code example:
NSMutableArray *bin = [NSMutableArray arrayWithObjects:#"0", #"1", #"2", #"3", #"4", #"5", #"6", #"7", nil];
NSMutableArray *list = [NSMutableArray arrayWithObjects:#"a1", #"b2", #"c3", #"e4", nil];
NSMutableArray *listHolder = list; // can't mutate 'list' within loop so create a holder
for (int i = 0; i < [list count]; i++) {
[listHolder replaceObjectAtIndex:i withObject:[bin objectAtIndex:i]];
}
What is that second array listHolder called? I mean, what term is used to refer to an array in this context.
This is perfectly valid:
NSMutableArray *bin = [NSMutableArray arrayWithObjects:#"0", #"1", …, #"7", nil];
NSMutableArray *list = [NSMutableArray arrayWithObjects:#"a1", …, #"e4", nil];
// NSInteger should be used instead of int
for (NSInteger i = 0; i < [list count]; i++) {
[list replaceObjectAtIndex:i withObject:[bin objectAtIndex:i]];
}
You're not allowed to change the array inside a for … in or NSEnumerate loop, but using an index is perfectly valid.
What troubles me is your misunderstanding of pointers.
If it were a loop in which you weren't allowed to mutate the array this wouldn't copy the array but only the pointer to the array, effectively modifying the array you're not allowed to. (I'm not even sure if this works.)
Instead of just copying the pointer
// can't mutate 'list' within loop so create a holder
NSMutableArray *listHolder = list;
make a true copy:
NSMutableArray *copy = [[list mutableCopy] autorelease];
In case I really have to make a copy I try to name it according to its content. For example:
NSMutableArray *views;
NSMutableArray *reorderedViews = [views mutableCopy];
// reorder reorderedViews
Sometimes it's hard to find a good enough name, then I usually just use nameCopy.
In this context listHolder would be called a copy.
Your code has a bug though. This line is not actually making a copy, it is only letting listHolder and list both reference the same array object:
NSMutableArray *listHolder = list;
This would be an actual copy:
NSMutableArray *listHolder = [list mutableCopy];
Make sure that you use mutableCopy and not just copy if you want the copy to be mutable. The copy method will return immutable variants on all mutable classes such as NSMutableSet, NSMutableDictionary, and so forth.
Also as others have noted it is only inside the for (item in collection) loop that the enumerated collection can not be mutated. In a normal for (;;) mutation is perfectly ok, but can lead to strange result if the number of items in the collection changes.
There is not specific stylistic or common name for this that is universally used, it is your code afterall, and if there appropriate terms for them use them.
Having said that generally if you don't have specific names in this sort of situation then people refer to the original list as the "source" (src) and the final list as "destination" (dst), just like in a memory blitting style operation.
A temporary mutable copy of the original NSArray would be how I would refer to it.