Adding NSString to NSMutableArray substitutes the previous NSString - iphone

I'm basically trying to add a new string to my NSMutableArray using this code in ViewWillAppear
NSUserDefaults *favBooksDefaults = [NSUserDefaults standardUserDefaults];
self.favBook = [favBooksDefaults stringForKey:#"favBook"];
self.favBookList = [[NSMutableArray alloc]init];
[self.favBookList addObject:favBook];
Of course, while I do this, I want to preserve ALL the previous strings that were present in the Array. Because when I add a new string for the NSUserDefaults and then to the Array, it simply substitutes the old one.
Why is that and how can I save all the objects?
Thanks in advance.

Mr Br.'s answer is correct:
In your header file declare favBookList as a property and include a book adding method:
#interface yourViewController : UIViewController {
NSMutableArray *favBookList;
}
-(void)addBook;
#property (nonatomic, retain) NSMutableArray *favBookList;
In your viewDidLoad method, initialize favBookList. Don't forget #synthesize!
-(void)viewDidLoad {
self.favBookList = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
Now you are free to add a book from your user defaults at any time.
-(void)addBook{
self.favBook = [[NSUserDefaults standardUserDefaults] stringForKey:#"favBook"];
[favBookList addObject:favBook];
}

When you alloc and init a new NSMutableArray object you will have an empty array with no values in it. It doesn't substitute it as there is nothing to substitute in there. It just adds the NSSString as the first value. This of course happens EVERY time you alloc/init a new instance of NSMutableArray.
SOLUTION: Make the NSMutableArray a instance variable of your view controller. alloc/init it once (e.g. in the viewDidLoad). Every time viewWillAppear gets called you can add values without reinitializing a new NSMutableArray.

NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray];
[newArray replaceObjectAtIndex:oldObjectIndex withObject:newObject] // if you want to replace oldObject with newObject;
[newArray addObject:newObject] // if you want to add object to the array;
If i get it right you want to replace the old object with new one?

NSUserDefaults *favBooksDefaults = [NSUserDefaults standardUserDefaults];
self.favBook = [favBooksDefaults stringForKey:#"favBook"];
if ([self.favBookList indexOfObject:self.favBook] != NSNotFound) {
[self.favBookList addObject:favBook];
}
You should also init your favBookList in viewDidLoad method:
self.favBookList = [NSMutableArray array];

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.

Why I can't access NSMutable Array in my method?

I try to add object to my NSMutable array in my method, but keep getting error. It works, if I add the object in init. It doesn't say that anything is wrong until I try to execute the code.
This is below the #import stuff where I declare two arrays:
NSMutableArray *actions1, *actions2;
This is in init:
actions1 = [NSMutableArray array];
Here I try to add 1 to the array:
- (void) storeAction:(int) action {
[actions1 addObject:#"1"];
}
The same code works in int as I said earlier.
I also would like it to store the int value declared "action", but this didn't seem to work either.
[addObject:#"%d", action];
[NSMutableArray array]; is returning an autoreleased object, by the time you try to access it, it is most likely deallocated already. Try [[NSMutableArray alloc] init]; instead. And than you should urgently check the memory management rules.
Try out this code
actions1 = [[NSMutableArray alloc] init];
Hope this helps.
Alternatively, in your header file:
#property(nonatomic, strong)NSMutableArray *actions1;
Then in the implantation file:
#synthesize actions1 = _actions1;
Then you can access your array as self.actions1.

Modifying an NSMutableArray inside a loop

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]]]

NSMutableArray not accessible throughout my class?

I'm really frustrated after spending like three hours googling around to solve this problem!! It's probably an easy solution to it aswell.
I'm creating a really simple TableView app for the iPhone. It's supposed to fetch an XML-document and parse it (already fixed) and then put the data into objects called HPobject!
One HPobject represents one day of data from the XML-file. Anyhow!
Then I want the object to be stored in a NSMutableArray so I can grab it later when I'm creating the table rows. But I can't access it! My NSMutableArray is ALWAYS null! No matter what I do!
Here's my code:
//THE .h FILE
#import "TBXML.h"
#import "HPobject.h"
#interface RootViewController : UITableViewController {
NSMutableArray *listOfItems;
}
- (void)traverseElement:(TBXMLElement *)element;
//THE .m FILE
#import "RootViewController.h"
#import "HPobject.h"
#implementation RootViewController
- (void)viewDidLoad
{
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
TBXML * tbxml = [[TBXML tbxmlWithURL:[NSURL URLWithString:#"http://www.hpprov.se/istasts.php?q=xxxxxxx"]] retain];
if (tbxml.rootXMLElement)
[self traverseElement:tbxml.rootXMLElement]; //Works fine!
[tbxml release];
[super viewDidLoad];
}
- (void) traverseElement:(TBXMLElement *)element {
do {
//Lots of parsing code which all works fine and gets me the variables up next!
HPobject *currentObject = [[HPobject alloc] init];
currentObject.antalRegistrerade = numRegistrerade;
currentObject.inkomstBrutto = numBrutto;
currentObject.inkomstNetto = numNetto;
[listOfItems addObject:currentObject];
NSLog(#"Array: %#", listOfItems); //RETURNS null!
NSLog(#"Reg: %#, Net: %#, Brutt: %#", currentObject.antalRegistrerade, currentObject.inkomstNetto, currentObject.inkomstBrutto); //Returns the correct values!
NSLog(#"%d stycken!", listOfItems.count); //Returns 0!! :(
[currentObject release];
} while ((element = element->nextSibling));
}
You are defining listOfItems locally in viewDidLoad and then you try to access that in another method.
Make sure you are using an instance variable defined in your interface definition (header).
replace this line in viewDidLoad:
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
with
listOfItems = [[NSMutableArray alloc] init];
I suppose that listOfItems is an ivar. So to fix your problem change this:
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
to this
listOfItems = [[NSMutableArray alloc] init];
Take a look at the scope of your array. You have created that as a variable of another method. It will not visible in others. Make an instance var.

How to add data to a TableView?

I've got a tableView in a view which is a subview to my MainViewController. When the subview is loaded, I have this in my viewDidLoad method to initialize my tableData:
NSMutableArray *array = [[NSMutableArray alloc] init];
self.listData = array;
[array release];
[super viewDidLoad];
Then I use other methods to add to this data within this view.
When I switch back to my other view, however, then bring up this view again, it initializes the data all over again, erasing my changes. How can I fix this problem?
EDIT:
I tried to initialize this array in MainViewController by doing this:
NSMutableArray *array = [[NSMutableArray alloc] init];
HistoryViewController.listData = array;
[array release];
But it says Accessing unknown 'setListData:' class method.
you should not be initializing your array in view did load
// this is clearing out all of your data
NSMutableArray *array = [[NSMutableArray alloc] init];
self.listData = array;
There is not much code, but I would suggest initializing the listData property when you initialize the ViewController.
I might suggest you review this tutorial here on UITableView, and your code above should be edited
HistoryViewController.listData = array;
should be
self.listData = array;