Modifying an NSMutableArray inside a loop - iphone

I have an NSMutableArray filled with Task objects. I want to be able to delete those whose completed property are set to YES
NSMutableArray *allTasks = (NSMutableArray *)[[TaskStore defaultStore] allTasks];
NSMutableArray *completedTasks;
for (Task *task in allTasks) {
if ([task completed]) {
[completedTasks addObject:task];
}
}
[allTasks removeObjectsInArray:completedTasks];
While debugging I noticed that the completedTasks array is always empty. Why is this?

You forgot to initialize the completedTasks :
NSMutableArray *completedTasks = [NSMutableArray array];

You haven't initialized completedTasks. You need to add this:
NSMutableArray *completedTasks = [[NSMutableArray alloc] init];

You must initialize the array before you can use it, the initializing actually creates your array object -
To do this add This Line to create an autoreleased array (which means you dont have to release it)
NSMutableArray *completedTasks = [NSMutableArray array];
Or
NSMutableArray *completedTasks = [[NSMutableArray alloc] init];
But then you will have to release it by yourself [completedTasks release] when you are not using it any moere (unless you are using ARC).
This will create your array object.
Shani

from NSMutableArray documentation :
This method assumes that all elements in otherArray respond to hash and isEqual:.
You can try :
[allTasks filterUsingPredicate:[NSPredicate predicateWithFormat:#"completed = %#", [NSNumber numberWithBool:YES]]]

Related

How to release an NSMutableArray?

I have an NSMutableArray with the following property:
#property (nonatomic, strong) NSMutableArray *alarmTableArray;
alarmTableArray = [[NSMutableArray alloc]init];
FMDBDatabaseAccess *db = [[FMDBDatabaseAccess alloc] init];
alarmTableArray = [db getAlarm];
I tried releasing this array but I end up with EXC_BAD_ACCESS.
I am really worried about this.
How to release this array?
You're using the descriptor of "strong" which is an ARC term. This should be retain and if you just set the property to nil it will release it automatically. You should set it to nil in your viewDidUnload since your ViewWillDissappear only means your viewcontroller is leaving visibility and not that it is being destroyed.
Updated Answer
I think I know what you're trying to do. You want grab an array of rows from your SQL and store it in one of your array.
One of the techniques for getting rows of data from SQL and storing into a class instance variable array is to NOT return a temporary array but pass the class instance variable array as a reference into your method and modify the array directly.
So instead of this pseudo-code
-(NSMutableArray *)doSomething
{
NSMutableArray *tempArray;
while (DB select statement has found rows)
{
CockTail *objCT = [[CockTail alloc] init];
objCT.name = #"...";
objCT.price = #"...";
[tempArray addObject:objCT];
[objCT release];
}
return [tempArray autorelease];
}
// class instance variable array
instanceVarArray = [[NSMutableArray alloc] init];
instanceVarArray = [self doSomething]; // here is where you confusion arise
You can do it this way:
-(void)doSomething:(NSMutableArray *)paramArray
{
// remove previously fetched data
[paramArray removeAllObjects];
SQL select statement
while(has rows)
{
CockTail *objCT = [[CockTail alloc] init];
objCT.name = #"...";
objCT.price = #"...";
// NOTE: we are directly modifying our class instance variable array
// here since it was passed by reference :D
// and so there is no need to worry about releasing the array
[paramArray addObject:objCT];
[objCT release];
}
}
// Now all you do is pass in your class instance variable array
instanceVarArray = [[NSMutableArray alloc] init];
[self doSomething:instanceVarArray];
Original Answer
Um, maybe I am wrong but aren't you essentially throwing away that "alloc init" on the first line here when you assign the array something from your FMDBDatabaseAccess:
// LINE 1: this instance of NSMutableArray here is allocated
alarmTableArray = [[NSMutableArray alloc]init];
// LINE 2
FMDBDatabaseAccess *db = [[FMDBDatabaseAccess alloc] init];
// LINE 3:this line here essential breaks the pointer link point to the NSMutableArray instance on line 1
alarmTableArray = [db getAlarm];
Now unless you do
// LINE 4
[alarmTableArray retain];
Otherwise, your alarmTableArray was never allocated (since you overwrote the pointer link). And as a result, you've caused a memory leak as your profiler told you.
Doing a release now would give your that EXEC_BAD_ACCESS
What I think you want to do is this:
alarmTableArray = [[NSMutableArray alloc]init];
FMDBDatabaseAccess *db = [[FMDBDatabaseAccess alloc] init];
// this now uses the setter method (mutator method generated by #property) to do the copy
self.alarmTableArray = [db getAlarm];
Looking at your while loop, I have to ask why are you releasing a local scope variable?
CockTail *cocktailValues = [[CockTail alloc] init];
...
[cocktails addObject:cocktailValues];
[cocktailValues release];
Breakdown of each line of code above:
When you alloc and init the CockTail object the release/retain count is 0.
Adding the object to the NSMutableArray increases the release/retain count to 1.
Releasing the CockTail object after you added it to array reduce the release/retain count back down to 0.
Therefore, later when you release the NSMutableArray or try to access an object in it, the objects are already gone.
Remember the number one rule, only release what you retain.

Select an array from an array of arrays to display in uitableview (iphone)

I have an array called addArray which I am adding array objects to:
NSMutableArray *addArray = [NSMutableArray array];
[addArray addObjectsFromArray: delegate.arrayobjectOne];
[addArray addObjectsFromArray: delegate.arrayobjectTwo];
// etc...
Now, if I only want to init one of these arrays to display in my table (preferably from another view controller but that's another question), how would I do this? And how would I access a specific property of each array object, e.g. arrayobjectOne.info?
Thanks for your time.
you can say
someObject = [addArray objectAtIndex: someIndex];
use this Example
NSMutableArray *objectsToAdd= [[NSMutableArray alloc] initWithObjects:#"one",#"two", nil];
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:objectsToAdd,nil];
self.list = [[NSMutableArray alloc] init];
[self.list addObjectsFromArray:myArray];

how to split string into NSMutableArray

I want to split string into NSMutableArray
I know
- (NSArray *)componentsSeparatedByString:(NSString *)separator
is available but this one is for NSArray not for NSMutableArray.
I need because after spliting i want to remove element from array by using
-(void)removeObjectAtIndex:(NSUInteger)index
which is not possible with NSArray.
Thank you
You can also just get a mutable copy of the returned array:
NSMutableArray *array = [[myString componentsSeparatedByString:#"..."] mutableCopy];
Also, remember that copy, like alloc, does allocate new memory. So when used in non-ARC code you must autorelease the copied array or manually release it when you are done with it.
Make a new NSMutableArray using
NSArray *array = [NSString componentsSeparatedByString:#"..."];
NSMutableArray *mutable = [NSMutableArray arrayWithArray:array];
Create a NSMutableArray from the output NSArray created by componentsSeparatedByString.
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];

nsmutablearray - Componentsseperatedbystring

How wouold i do this with a nsmutablearray, its simple with a nsarray just not a mutable array
Thanks
Just create mutable array from non-mutable that you get from that message:
NSMutableArray *mutableComponents = [NSMutableArray arrayWithArray:[yourString componentsSeparatedByString:...]];
The following will work too:
NSMutableArray *mArray = (NSMutableArray *)[yourString
componentsSeparatedByString:#"separator"];
You might need to retain and release when you're done.
Use the following code.
NSArray *array = [someString componentsSeparatedByString:#" "];
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithArray:array];
use the mutArray, this is one NSMutableArray object.

Building an array of arrays

I am trying to get the following loop working to fill an array of arrays:
while (condition) {
[itemsArray fillFromDB];
if (! [checkArray containsObject:checkFlag]) {
// Add existing itemsArray to myArray
if (itemsArray.count) {
// add the itemsArray to myArray and create a new instance of itemsArray
[myArray addObject:itemsArray];
[itemsArray release];
NSMutableArray *itemsArray = [[NSMutableArray alloc] init];
}
[itemsArray addObject:myObject];
[checkArray addObject:checkFlag];
} else {
[itemsArray addObject:tmpEvent];
} }
However I try to shape this loop it falls over the release of itemsArray
when I use release (as above), the array does not re-initialise as a new instance with alloc. Whilst expecting emptyness, the next Object is added to the old array.
when I use removeAllObjects, my Array is emptied and so is the array attached to myArray.
Where am I going in the wrong direction?
You might place:
itemsArray = nil;
after the release message, to ensure that you're not pointing to an old instance.
EDIT
Looking at this again, you have:
NSMutableArray *itemsArray = [[NSMutableArray alloc] init];
This is scoped within the if statement.
So take out NSMutableArray and just use:
itemsArray = [[NSMutableArray alloc] init];
Don't write NSMutableArray *itemsArray = [[NSMutableArray alloc] init];--you're re-declaring the variable in the scope of the if statement, so outside the if statement, itemsArray will still refer to the old value (I'm not sure why the compiler isn't complaining). You can just say itemsArray = [[NSMutableArray alloc] init] instead.
You also might want to use autorelease, to simplify, as well.
The others have found the problem, but have created a new problem. The first time you create the mutable array, you need to use NSMutableArray *itemsArray = [[NSMutableArray alloc] init];. Then, after, you can release and use itemsArray = [[NSMutableArray alloc] init];. It is important that the first one (the one that creates the pointer) occurs only once, and the rest can occur as many times as desired.
EDIT:
You could write NSMutableArray *itemsArray; before the if statement, and then use itemsArray = [[NSMutableArray alloc] init]; in the if statement.