Question

Edit: Using nested arrays and accessing via index, I have this so far:

int currentHole = [holeLabel.text intValue];
holes = [[NSMutableArray alloc] init];
players = [[NSMutableArray alloc] init];
[holes addObject:players];

for (int i=0; i<=5; i++) {

        NSIndexPath *indexPath = [NSIndexPath indexPathForRow: i inSection: 0];
        UITableViewCell *cell = [table cellForRowAtIndexPath:indexPath];

        for (UIView *view in  cell.contentView.subviews){

            if ([view isKindOfClass:[UITextField class]]){

                UITextField* txtField = (UITextField *)view;

                if (txtField.tag == 6) {
                    int playerOneValue = [txtField.text intValue];
                    NSNumber *oneNumber = [NSNumber numberWithInteger:playerOneValue];
                    [players insertObject:oneNumber atIndex:0];
                }
           }
      }
}

I have a minigolf scorekeeping app that has a single table view that changes hole number when you swipe left or right (up to 18 holes). I want to save the strokes from the text fields for each user (up to six) and when the user swipes back to a certain hole I want to retrieve the stroke values saved to the corresponding hole's dictionary (e.g. Dict 4 for Hole 4). What is the most efficient way to do this?

In the method called when the user swipes back I have:

//Array containing the strokes for the hole
holes = [[NSMutableArray alloc] init];
        for (int i=0; i<=5; i++) {

// Go through each text field (with strokes) for the six players
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow: i inSection: 0];
            UITableViewCell *cell = [table cellForRowAtIndexPath:indexPath];

            for (UIView *view in  cell.contentView.subviews){
                if ([view isKindOfClass:[UITextField class]]){

                    UITextField* txtField = (UITextField *)view;

                    if (txtField.tag == 6) {
// Add the stroke status for each player to the holes array (then written to plist)
                        [holes addObject:txtField.text];
                        txtField.text = @"";
                    }
                    if (txtField.tag == 7) {
                        [holes addObject:txtField.text];
                        txtField.text = @"";
                    }
                    if (txtField.tag == 8) {
                        [holes addObject:txtField.text];
                        txtField.text = @"";
                    }
                    if (txtField.tag == 9) {
                        [holes addObject:txtField.text];
                        txtField.text = @"";
                    }
                    if (txtField.tag == 10) {
                        [holes addObject:txtField.text];
                        txtField.text = @"";
                    }
                    if (txtField.tag == 11) {
                        [holes addObject:txtField.text];
                        txtField.text = @"";
                    }
                }
            }
        }

//String unique to each hole (e.g. Hole 12)
        NSString *holeName = [NSString stringWithFormat:@"Hole %@", holeLabel.text];
        // create dictionary with values in UITextFields
        NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:holes, nil]
                                                              forKeys:[NSArray arrayWithObjects: holeName, nil]];

        NSString *error = nil;
        // create NSData from dictionary
        NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0
                                                             errorDescription:&error];

        // check is plistData exists
        if(plistData)
        {
            // write plist date to plist file
            [plistData writeToFile:plistPath atomically:YES];
            NSLog(@"plist written");
        }
        else
        {
            NSLog(@"Error in saveData: %@", error);
        }

Accessing the data from the plist file - gets the array in the plist dict to access from the current hole:

NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"Scores List.plist"];

// check to see if Scores List.plist exists in documents
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
    // if not in documents, get property list from main bundle
    plistPath = [[NSBundle mainBundle] pathForResource:@"Scores List" ofType:@"plist"];
}

//Get hole string to search array from
NSString *holeString = [NSString stringWithFormat:@"Hole %@", holeLabel.text];
// read property list into memory as an NSData object
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
// convert static property liost into dictionary object
NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML
                                                                      mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                                                format:&format errorDescription:&errorDesc];
if (!temp)
{
    NSLog(@"Error reading plist: %@, format: %lu", errorDesc, format);
}

holes = [NSMutableArray arrayWithArray:[temp objectForKey:holeString]];
NSLog(@"plist read");
for (int i=0; i<=5; i++) {

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow: i inSection: 0];
    UITableViewCell *cell = [table cellForRowAtIndexPath:indexPath];

    for (UIView *view in  cell.contentView.subviews){
        if ([view isKindOfClass:[UITextField class]]){

            UITextField* txtField = (UITextField *)view;

            if (txtField.tag == 6) {
                //Write the plist strokes integers to the strokes text boxes for each player
                txtField.text = [holes objectAtIndex:0];
            }
            if (txtField.tag == 7) {
                txtField.text = [holes objectAtIndex:1];
            }
            if (txtField.tag == 8) {
                txtField.text = [holes objectAtIndex:2];
            }
            if (txtField.tag == 9) {
                txtField.text = [holes objectAtIndex:3];
            }
            if (txtField.tag == 10) {
                txtField.text = [holes objectAtIndex:4];
            }
            if (txtField.tag == 11) {
                txtField.text = [holes objectAtIndex:5];
            }
        }
    }
}

This code works for retrieving the previous hole's strokes when swiping back a hole, but if you swipe back again the app crashes, with an error stating that the array is empty and could not access the value at index 1. I'm sure there's a better method for what I need to do though other than a plist.

Was it helpful?

Solution

Instead of plist file which is a dictionary, you should go with array only. Create an array having 18 objects inside it. These objects represent the 18 holes. Just access those object using index(hole which you want to observe) instead of creating a key.

Now each object inside the array is also an array which represents number of players. The index of the array represents the player.

Create an instance variable as holes of type NSMutableArray. Initialise it in below way.

 holes = [[NSMutableArray alloc]init];
 for(int hole = 0; hole < TOTAL_HOLES; hole++)
 {
      NSMutableArray *persons = [[NSMutableArray alloc]init];
      for(int player = 0; player < TOTAL_PLAYERS; player++)
      {
           NSNumber *score = [NSNumber numberWithInt:-1];
           [persons addObject:score];
      }
      [holes addObject:persons];
 }

Now each object of array holes represents the score of each players for that particular hole. Initial value is set to -1 which means the score of that player for that particular hole is not entered yet. When you want to modify the score of any particular player for any particular hole, you can do it by below way.

 NSNumber *score = [NSNumber numberWithInt:SCORE_OF_PLAYER];
 NSMutableArray *scoresForHole = [holes objectAtIndex:SCORE_OF_PLAYER_FOR_HOLE];
 [scoresForHole replaceObjectAtIndex:PLAYER_NUMBER withObject:score];
 [holes replaceObjectAtIndex:3 withObject:scoresForHole];

So, overall structure will become,

[0] = {0,1,2,3... total players},
[1] = {0,1,2,3... total players},
.
.
.
[17] = {0,1,2,3... total players}

Now when you want to access player 5 record for hole number 8, you can do following,

[[holes objectAtIndex:holeNum] objectAtIndex:playerNum];

To write down the array into a file and to initialise the array from file, you can use library routines of array class. Hope that will simplify your problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top