Saving and restoring NSMutablearray to NSUserdefaults - ios

I am writing a app that needs to save and restore nsmutablearrays to populate a table view. The array will save but won't overwrite once i reset everything. i find that the values are combining together and is giving me unreliable averages... code is below. also i have various view controllers that have this lap function...
// code that adds items to table view and saves a version of the array to nsmutablearray
NSUserDefaults *prefs = [[NSUserDefaults alloc]
initWithSuiteName:#"group.com.DJ.TSTML"];
[tableItems3 insertObject:TimeString2 atIndex:0];
// time string is the time as a nsstring
[tableItems4 addObject:[NSNumber numberWithFloat:seconds2]];
[tableview reloadData];
[prefs setObject:self.tableItems4 forKey:#"SavedArray3"];
[prefs setObject:self.tableItems3 forKey:#"SavedArray4"];
// this is saving to insurer defaults
NSString *newString = [NSString stringWithFormat:#"%lu", (unsigned long)tableItems3.count];
[Commentcount setText:newString];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSNumber *average = [tableItems4 valueForKeyPath:#"#avg.self"];
Average.text = [formatter stringFromNumber:average];
NSLog(#"Sucess");
[prefs synchronize];
} }
Restoring the array :
NSUserDefaults *prefs = [[NSUserDefaults alloc]
initWithSuiteName:#"group.com.DJ.TSTML"];
// code used to erase current values in the table view and restore from NSUserDefaults
tableItems3 = [[NSMutableArray alloc] init];
tableItems4 = [[NSMutableArray alloc] init];
[tableview reloadData];
NSMutableArray *RestoreArray1 = [[prefs objectForKey:#"SavedArray4"]mutableCopy];
NSMutableArray *RestoreArray2 = [[prefs objectForKey:#"SavedArray3"]mutableCopy];
[tableItems3 addObjectsFromArray:RestoreArray1];
[tableItems4 addObjectsFromArray:RestoreArray2];
if (tableItems3 == nil) {
tableItems3 = [[NSMutableArray alloc] init];
tableItems4 = [[NSMutableArray alloc] init];
}
[tableview reloadData];
NSLog(#"%#",tableItems4);
}
}
Thank you in advance for any help!
My issue to be clear is that every time i save to nsuserdefaults instead of overwriting the previous array it just keeps the old array and combines with the new one

Ok so i answered my own question. As someone brought up it was combining because i was retrieving without overwriting it first. the following code is what worked...
NSString *Clearstring = [prefs objectForKey:#"Clear?"];
// i created a nsstring that when the method for restarting would change accordingly.
// so when someone would navigate to this view controller this would fire.
// if clear is yes i would prevent the code that controled the restore function from restoring and prepare
// it if it was needed to be restored again.
if ([Clearstring isEqualToString:#"Yes"]) {
tableItems3 = [[NSMutableArray alloc] init];
tableItems4 = [[NSMutableArray alloc] init];
[prefs setObject:self.tableItems4 forKey:#"SavedArray3"];
[prefs setObject:self.tableItems3 forKey:#"SavedArray4"];
[prefs setObject:#"NO" forKey:#"Clear?"];
[tableview reloadData];
}
else{
tableItems3 = [[NSMutableArray alloc] init];
tableItems4 = [[NSMutableArray alloc] init];
[tableview reloadData];
NSMutableArray *RestoreArray1 = [[prefs objectForKey:#"SavedArray4"]mutableCopy];
NSMutableArray *RestoreArray2 = [[prefs objectForKey:#"SavedArray3"]mutableCopy];
[tableItems3 removeAllObjects];
[tableItems4 removeAllObjects];
[tableItems3 addObjectsFromArray:RestoreArray1];
[tableItems4 addObjectsFromArray:RestoreArray2];
if (tableItems3 == nil) {
tableItems3 = [[NSMutableArray alloc] init];
tableItems4 = [[NSMutableArray alloc] init];
}
[tableview reloadData];
NSLog(#"%#",tableItems4);
}
}

Related

How to replace NSMutableArray List data

I am very new for IOS. In my app, I have inserted two UIButtons on my mainViewController
When I click first button I am adding some data in my Main NSMutableArray and when I click "second" button I want remove previous array details and replace new data.
My code:
- (void)viewDidLoad {
[super viewDidLoad];
mainArray = [[NSMutableArray alloc] init];
}
- (IBAction)button1:(id)sender{
NSMutableArray * data1 = [[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3", nil];
[mainArray replacementObject:data1];
}
- (IBAction)button2:(id)sender{
NSMutableArray * data2 = [[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
[mainArray removeObjectAtIndex:data2];
}
Please help.
Try this code
- (IBAction)button1:(id)sender{
NSMutableArray * data1 = [[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3", nil];
[mainArray addObject:data1];
}
- (IBAction)button2:(id)sender{
NSMutableArray * data2 = [[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
[mainArray replaceObjectAtIndex:0 withObject:data2];
}
I assumed your mainArray contains only one element. If there are more elements you need to specify correct index
Try This one:
- (IBAction)button1:(id)sender{
[mainArray addObjectsFromArray:[[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3", nil]];
}
- (IBAction)button2:(id)sender{
[mainArray replaceObjectsInRange:NSMakeRange(0, mainArray.count) withObjectsFromArray:[[NSMutableArray alloc]
initWithObjects:#"6",#"2",#"3",#"4",#"5", nil]];
}
- (void)viewDidLoad {
[super viewDidLoad];
mainArray = [[NSMutableArray alloc]init];
}
- (IBAction)button1:(id)sender{
mainArray = [[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3", nil];
}
- (IBAction)button2:(id)sender{
mainArray = [[NSMutableArray alloc]
initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
}

Why my array of NSDictionary lost its objects?

I'm having a difficulty with this one I have a method that returns a value of Array of NSDictionary once I pass the return value of an array first it works. I already get the object in my NSLog but when I try to access the objects of my Array of NSDictionary in another method I get the error and I think that I loses the objects of the array.
Here's the method that return an Array of NSDictionary:
-(NSMutableArray *)selectItemDataTbl {
NSMutableArray *l_array_data = [[NSMutableArray alloc] init];
NSString *query = #"SELECT pid, fname, gen_name, type, fu, fprice FROM tbl_selectItem_data";
sqlite3_stmt *l_statement;
if (sqlite3_open([l_SqliteDb UTF8String], &(_database)) == SQLITE_OK) {
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &l_statement, nil) == SQLITE_OK) {
while(sqlite3_step(l_statement) == SQLITE_ROW){
NSMutableDictionary *l_dataDictionary = [[NSMutableDictionary alloc]init];
NSString *l_pid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(l_statement, 0)];
NSString *l_name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(l_statement, 1)];
NSString *l_genName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(l_statement, 2)];
NSString *l_Type = [NSString stringWithUTF8String:(char *)sqlite3_column_text(l_statement, 3)];
NSString *l_u = [NSString stringWithUTF8String:(char *)sqlite3_column_text(l_statement, 4)];
NSString *l_Price = [NSString stringWithUTF8String:(char *)sqlite3_column_text(l_statement, 5)];
[l_dataDictionary setObject:l_pid forKey:#"pid"];
[l_dataDictionary setObject:l_name forKey:#"name"];
[l_dataDictionary setObject:l_genName forKey:#"genName"];
[l_dataDictionary setObject:l_Type forKey:#"Type"];
[l_dataDictionary setObject:l_u forKey:#"u"];
[l_dataDictionary setObject:l_Price forKey:#"Price"];
[l_array_data addObject:l_dataDictionary];
}
NSLog(#"l_array_data count: %i", [l_array_data count]);
sqlite3_finalize(l_statement);
sqlite3_close(_database);
}
}
return l_array_data;
}
And here my method how I access it I'm calling it on my viewDidLoad:
- (void)selectItemData {
_l_alldataInSelectItem = [[NSMutableArray alloc] init];
_l_prodId = [[NSMutableArray alloc] init];
_l_prodName = [[NSMutableArray alloc] init];
_l_prodGenName = [[NSMutableArray alloc] init];
_l_prodCompType = [[NSMutableArray alloc] init];
_l_prodUom = [[NSMutableArray alloc] init];
_l_prodListPrice = [[NSMutableArray alloc] init];
_l_alldataInSelectItem = [dbc selectItemDataTbl];
_l_selectItemData_Dictionary = [[NSDictionary alloc] init];
for (_l_selectItemData_Dictionary in _l_alldataInSelectItem) {
NSString *Id = [_l_selectItemData_Dictionary valueForKey:#"pid"] ;
NSString *Name = [_l_selectItemData_Dictionary valueForKey:#"name"];
NSString *GenName = [_l_selectItemData_Dictionary valueForKey:#"genName"];
NSString *Type = [_l_selectItemData_Dictionary valueForKey:#"Type"];
NSString *U = [_l_selectItemData_Dictionary valueForKey:#"u"];
NSString *Price = [_l_selectItemData_Dictionary valueForKey:#"Price"];
[_l_prodId addObject:Id];
[_l_prodName addObject:Name];
[_l_prodGenName addObject:GenName];
[_l_prodCompType addObject:GenName];
[_l_prodUom addObject:U];
[_l_prodListPrice addObject:Price];
}
NSLog(#"adsfasdf %#", _l_prodId);
NSLog(#"adsfasdf %i", [_l_alldataInSelectItem count]);
}
But in this method I can't get the value of my array _l_alldataInSelectItem
- (void)textFieldshouldChange {
NSString *searchKey = self.txt_SearchField.text;
NSMutableArray *searchingData = [[NSMutableArray alloc] init];
if (![searchKey isEqualToString:#""]) {
NSLog(#"When TextField text is changed, this will be called");
NSLog(#"textFieldshouldChange _l_alldataInSelectItem: %i", [_l_alldataInSelectItem count]);
}
}
here's how i declare my l_alldataInSelectItem. I declared it on my header file
#property (strong, nonatomic) NSMutableArray *l_alldataInSelectItem, *l_prodId, *l_prodName, *l_prodGenName, *l_prodCompType, *l_prodUom, *l_prodListPrice;
Go systematically through the possibilities.
Possibility 1: There are gremlins somewhere trying to annoy you. We exclude that.
Possibility 2: You never created the data. Set a breakpoint on the return statement in selectItemDataTbl and check it.
Possibility 3: You never stored the array. Well, there is the fact that you store an empty mutable array into _l_alldataInSelectItem which is absolutely pointless, but set a breakpoint on the last statement in selectItemData and check it.
Possibility 4: You stored it and overwrote it. Search for all places where you store to _l_alldataInSelectItem or to a property named l_alldataInSelectItem, set breakpoints everywhere, and check.
Possibility 5 (the stupid one): _l_alldataInSelectItem is a weak instance variable or a weak property.
Possibility 6: You stored it, but looked for it in a different place. Is the self in textFieldshouldChange the same as the self in selectItemData? Set breakpoints and check.
Possibility 7: You are doing something asynchronously. The variable will be set, but much later than you think.
Most important: Put it very strongly in your mind that you did something wrong, and you don't have to solve any magical puzzles, all you need to do is find out what you did wrong.

How to reparse xml data in tableView?

I have a tableView where the user can add contacts to. These contacts get saved to a mysql database and then returned to the user. Thing is, he has to update it manually in order to get the updated xml. But I wanna do it when he adds a contact so it gets shown right away. I tried various things and always ended up with either an error or he parsed the database more than once in the tableview. I thought of deleting all contacts and pasting all of them again and then update it, but this also didn't really work.
Here is how I do it at the moment:
To parse the XML:
- (void) doXMLParsing
{
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"Key22"] == nil) {
} else {
self.filteredListContent = [NSMutableArray arrayWithCapacity:[self.tabelle count]];
self.tableView.scrollEnabled = YES;
tabelle = [[NSMutableArray alloc] init];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *fileName = [prefs stringForKey:#"Key22"];
NSString *urlString = [NSString stringWithFormat: #"http://www.---.com/%#.xml", fileName];
NSURL *url = [NSURL URLWithString: urlString];
DataFileToObjectParser *myParser = [[DataFileToObjectParser alloc] parseXMLAtUrl:url toObject:#"Telefonbuch" parseError:nil];
for(int i = 0; i < [[myParser items] count]; i++) {
Telefonbuch *new = [[Telefonbuch alloc] init];
new = (Telefonbuch *) [[myParser items] objectAtIndex:i];
[tabelle addObject:new];
[self.tableView reloadData];
}
[XMLActivity stopAnimating];
}
}
In the viewDidLoad:
XMLActivity = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(140.0f, 290.0f, 40.0f, 40.0f)];
[XMLActivity setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:XMLActivity];
[XMLActivity startAnimating];
[self performSelector:#selector(doXMLParsing)
withObject:nil
afterDelay:0];
return;
tabelle = [[NSMutableArray alloc] init];
Everything works fine right now. I just want to reparse the XML after a new contact is added so it will get displayed right away.
Have you tried calling [reloadData][1] on your UITableView?
If this does not answer, could you explain what happens exactly when you parse xml a second time?
The solution was as obvious as simple, and I still wasted way too many time on this.
Here is the solution:
Just put
[self doXMLParsing];
at the end when you added a contact to the database.

When NSDictionary is added to array, it replaces the previous dictionary

UPDATE: Figured out some stuff and changed code.
When I add my NSDictionary to my array it suddenly replaces the previous dictionary I added last time. I don't know why this is happening. I am using a plist as data storage.
I get a error message like this:
Thread 1:Program received signal: "EXC_BAD_ACCESS".
Init
-(id)init{
self=[super init];
if(self){
dbArray = [[NSMutableArray alloc] init];
}
return self;
}
Adding a new item.
-(void)addNewItem:(NSString *)aString
{
// Creates a mutable dictionary with a anonymous string under the NAME key.
NSDictionary *newString = [[NSDictionary alloc] initWithObjectsAndKeys:aString,#"name", nil];
// Adds the new string to empty dbArray.
[dbArray addObject:(newString)];
NSLog(#"[add]:Added anonymous string to dbArray, under name key.");
// Writes the current dbArray (with the dict) to plist and releases retain counts.
[self writeItem];
[newString release];
}
My method to view my data.
-(void)viewData
{
// View data from the created plist file in the Documents directory.
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *finalPath = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:finalPath]) {
self.dbArray = [NSMutableArray arrayWithContentsOfFile:finalPath];
}
else {
self.dbArray = [NSMutableArray array];
}
}
instead this
self.dbArray = [[NSMutableArray alloc] init];
use this
if( nil == self.dbArray ) {
self.dbArray = [[NSMutableArray alloc] init];
}
UPDATE: (based on provided code)
you're using different instances of DataObject class for displaying & saving data. Your content is over-written, because you don't load data from file during initialization of each instance; to fix that fast, you need to implement init method of your DataObject class as below:
- (id)init{
self = [super init];
if(self){
[self viewData];
}
return self;
}
the following code from viewDidLoad of ViewController class will crash your application very often:
db = [[DataObject alloc] init];
[db viewData];
[db release];
array = [[NSMutableArray alloc] initWithArray:[db dbArray]];
replace it with
db = [[DataObject alloc] init];
[db viewData];
array = [[NSMutableArray alloc] initWithArray:[db dbArray]];
call [db release] only in dealloc implementation
another problem, that you'll probably arise - is updated data is not displayed when you're back to the main screen; to fix that add the following method implementation to your ViewController.m file:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[db viewData];
self.array = [NSMutableArray arrayWithArray: db.dbArray];
[self.tableView reloadData];
}
also in AddView.m replace the following code
// Dismiss view and reload tableview.
ViewController *vc = [[ViewController alloc] init];
[self dismissModalViewControllerAnimated:YES];
[vc release];
with
// Dismiss view and reload tableview.
[self dismissModalViewControllerAnimated:YES];
Just as advise: see more information about using delegates and passing object instances & copies between objects.
I think you are creating a new Array:
self.dbArray = [[NSMutableArray alloc] init];
You should create the dbArray on the viewDidLoad or on the init of your UIViewController (I am assuming you are using this on an UIViewController)
inside your DataObject do the following:
-(id)init{
self=[super init];
if(self){
self.dbArray = [[NSMutableArray alloc] init];
}
return self;
}

Can I release an object which was added to a NSMutableArray or does this affect a crash?

I've got one question about the memory management of the NSMutableArray. I create an object of my custom class and add this object to a NSMutableArray. Is this automatically retained, so that I can release my created object?
Thanks!
Yes, it is automatically retained. You should release your object after adding it to the array (or use autorelease)
For example:
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[[[MyClass alloc] init] autorelease]];
// or
MyClass * obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
Yes, you can do this for example:
NSMutableArray *array = [[NSMutableArray alloc] init];
NSString *someString = #"Abc";
[array addObject:someString];
[someString release];
NSLog(#"Somestring: %#", [array objectAtIndex:0]);

Resources