Chase
Chase

Reputation: 11

UITableView Cell not saving data correctly?

In my application, I have a UITableView and 2 buttons "Save" and "Load". In my case, when the user saves his or her track, my UITableView adds a new cell with the title of their track, then when the user taps the cell, it will re-load their track. This is working fine, but whenever the user saves one track, then tries to save another, the newly added cell re-loads only one track. So, my tableview can have 10 cells that have names, but whenever you tap on one, only one track is saved. So my question is, How can I save data for each cell? Here is my save function:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:NSStringFromCGPoint(ball.center) forKey:@"ballPosition"];
[userDefaults synchronize];

NSUserDefaults *block1DF = [NSUserDefaults standardUserDefaults];
[block1DF setObject:NSStringFromCGPoint(block1.center) forKey:@"block1Position"];
[block1DF synchronize];

NSUserDefaults *block2DF = [NSUserDefaults standardUserDefaults];
[block2DF setObject:NSStringFromCGPoint(block2.center) forKey:@"block2Position"];
[block2DF synchronize];

NSUserDefaults *block3DF = [NSUserDefaults standardUserDefaults];
[block3DF setObject:NSStringFromCGPoint(block3.center) forKey:@"block3Position"];
[block3DF synchronize];

NSUserDefaults *winBlockDF = [NSUserDefaults standardUserDefaults];
[winBlockDF setObject:NSStringFromCGPoint(winBlock.center) forKey:@"winBlockPosition"];
[winBlockDF synchronize];

NSString *trackName = [[alertView textFieldAtIndex:0] text];
trackTitle.text = trackName;

[trackArray addObject:[NSString stringWithFormat:trackName,[trackArray count]+1]];
[self.myTableView reloadData];

then my tableView didSelectRowAtIndexPath:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
CGPoint ballPoint = CGPointFromString([userDefaults objectForKey:@"ballPosition"]);
[ball setCenter:ballPoint];

NSUserDefaults *block1DF = [NSUserDefaults standardUserDefaults];
CGPoint block1Point = CGPointFromString([block1DF objectForKey:@"block1Position"]);
[block1 setCenter:block1Point];

NSUserDefaults *block2DF = [NSUserDefaults standardUserDefaults];
CGPoint block2Point = CGPointFromString([block2DF objectForKey:@"block2Position"]);
[block2 setCenter:block2Point];

NSUserDefaults *block3DF = [NSUserDefaults standardUserDefaults];
CGPoint block3Point = CGPointFromString([block3DF objectForKey:@"block3Position"]);
[block3 setCenter:block3Point];

NSUserDefaults *winBlockDF = [NSUserDefaults standardUserDefaults];
CGPoint winBlockPoint = CGPointFromString([winBlockDF objectForKey:@"winBlockPosition"]);
[winBlock setCenter:winBlockPoint];

Upvotes: 0

Views: 150

Answers (1)

Patrick Tescher
Patrick Tescher

Reputation: 3447

The reason you can only save one copy of your data is not because you have a bug. Its because NSUserDefaults can only save one version of "ballPosition". Anytime you save another "ballPosition" it will replace your existing "ballPosition".

I would suggest not using NSUserDefaults at all. Generally when you want to save lots of versions of similar data you want to use Core Data.

A good tutorial is here http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started BUT if you want the quick overview here it is:

If you create a new project in Xcode, choose Master-Detail Application and select Use Core Data you will have a new core data backed application.

This demo application creates a table of "Event" objects, each with a property called "timestamp".

Every time you hit the Add button the following code is run:

- (void)insertNewObject:(id)sender
{
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
    NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

    // If appropriate, configure the new managed object.
    // Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
    [newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];

    // Save the context.
    NSError *error = nil;
    if (![context save:&error]) {
         // Replace this implementation with code to handle the error appropriately.
         // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
}

This creates a new Event object, sets the current date for the key timeStamp, and saves the object to the local database.

A huge advantage here is that you are now perfectly using the MVC or Modal View Controller architecture pattern. You have a whole modal (and database) layer that works independently from your views and your controllers.

You are also using UITableViews correctly, you have an NSFetchedResultsController which will keep your table up to date anytime anything changes, and you have a separate detail view to display items in your table.

A few things to keep in mind with Core Data:

  1. You have a schema for your database. You can edit your schema from the xcdatamodeld file in Xcode. Anything you store in your model must be defined here.
  2. If you are just messing around you can reinstall your app any time you change your xcdatamodel and it will work fine, otherwise you need to deal with migrations and different versions of your schema.
  3. Core data is not the easiest tool to lear, but once you learn it you will have a much better starting point when creating apps.

Upvotes: 1

Related Questions