Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 09-07-2011, 01:50 PM   #1 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 16
Falimond is on a distinguished road
Unhappy Saving/Loading Integer Array into plist

I'm making a game and it features three different difficulty modes. Each difficulty mode contains 48 different levels each with their own selectable image. When a user beats a level that image changes so the user know they've already beat that level. I need to save each mode state in an integer array to display the correct level screen.

Given three mode arrays each initialized with all 0's when the user opens the app for the first time....
int beatEasyLevels[48];
int beatHardLevels[48];
int beatExpertLevels[48];

this is what I have pieced together from a video tutorial I found...

View.h
Code:
-(NSString *)pathOfFile;
-(void)applicationWillTerminate:(NSNotification*)notification;
View.m
Code:
-(NSString *)pathOfFile
{
	NSArray *path = NSSearchPathForDirectoriesInDomain(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentFolder = [path objectAtIndex:0];
	return [documentFolder stringByAppendingFormat:@"myfile.plist"];	
}

-(void)applicationWillTerminate:(NSNotification*)notification
{
	NSMutableArray *array = [[NSMutableArray alloc] init];
        [array addObject:beatEasyLevels];   
        [array addObject:beatHardLevels];   
	[array addObject:beatExpertLevels];         

 //How do I add these int array correctly? ^^^

	[array writeToFile:[self pathOfFile] atomically:YES];
	[array release];
}


-(void) viewDidLoad
{

if(difficultyMode == 0) //Easy difficulty
{

	NSString *filePath = [self pathOfFile];
	if ([[NSFileManager defaultManager]fileExistsAtPath:filePath])
	{
		NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
		int tempArray[48] = {[array objectAtIndex:0]};           

//How do load the same array from the file into a tempArray that I will use to display the correct beat/unbeat levels? 

		[array release];
	}
}
else if(difficultyMode == 1) //Hard difficulty
{

	NSString *filePath = [self pathOfFile];
	if ([[NSFileManager defaultManager]fileExistsAtPath:filePath])
	{
		NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
		int tempArray[48] = {[array objectAtIndex:1]};           
		[array release];
	}
}
else if(difficultyMode == 2) //Expert difficulty
{

	NSString *filePath = [self pathOfFile];
	if ([[NSFileManager defaultManager]fileExistsAtPath:filePath])
	{
		NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
		int tempArray[48] = {[array objectAtIndex:2]};           
		[array release];
	}
}	
	UIApplication *app = [UIApplication sharedApplication];
	[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app];

Another issue that I see with this where to initialize the beat(Mode)Levels arrays to 0 the first time the user opens the app but never again. Since after the first time the int arrays should be loaded from memory (hence the above issue).
Falimond is offline   Reply With Quote
Old 09-07-2011, 02:51 PM   #2 (permalink)
Registered Member
 
Join Date: Jul 2011
Posts: 241
MattW is on a distinguished road
Default

I'm not 100% sure I understand your problem, but if it's to do with storing your level arrays in another array, you've got 2 options:

1) Store your data as NSMutableArrays instead of int xxx[y]. If you do this, you can simply add the NSMutableArray to the array you're going to write out.

2) If you want to keep your array stored as int xxx[y], when you need to add it to your write-out array, you'll have to iterate over every value in each array with a for loop, like:

Code:
int i;

for (i=0; i<48; i++)
  [array addObject:[NSNumber numberWithInt:beatEasyLevels[i]]];

for (i=0; i<48; i++)
  [array addObject:[NSNumber numberWithInt:beatHardLevels[i]]];

for (i=0; i<48; i++)
  [array addObject:[NSNumber numberWithInt:beatExpertLevels[i]]];
Personally, I'd go for option 1 - it keeps things nice and clean, and this doesn't sound like performance-critical code.

As for your second question: When you come to populate the array (in viewWillAppear(), or whatever), if the file exists use that data, if not your array will be all zeroes - all Objective C class variables are initialized to 0 by the compiler.
__________________

Highlight PDF text like no other app: iHighlight (now available for iPad and iPhone!)
-----
Create iPhone lists with no typing: Insta-List
-----
Make spelling fun, and create your own tests: iWillSpell
-----
A fast, elegant flashlight app: Insta-Light
-----


FourSixteen Productions
MattW is offline   Reply With Quote
Old 09-07-2011, 03:59 PM   #3 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 16
Falimond is on a distinguished road
Default

Thanks for the quick reply. I'm going to go with the first implementation you suggested.

I did some searching on adding integers to NSMutableArrays and found that they need to have NSNumber formats. So if I initiate the mode arrays like so...
Code:
 
NSMutableArray *EasyMode = [NSMutableArray arrayWithCapacity:48];
You said each element in the array will automatically be 0. But THIS POST says that if I initiate the array with some capacity then there's no way to insert a number at any index of my choosing. And I have to be able to do that. The post suggests initiating the array with some placeholders instead. I can work with that because the elements in the array are either 0 or 1 so they could be 8 and 1 (for example).

I also found that if I want to place numbers in the array they must be NSNumbers. So I would need to do something like...
Code:
for(int i = 0;i < 49;i++)
{ NSMutableArray *EasyMode = [NSMutableArray EasyMode];
[EasyMode addObject:[NSNumber numberWithInt:8]];  }
Then let's say the user is playing level 5 of EasyMode and they've beaten it, this is on the Game Screen. So the view switches to the Level Screen where all this code will be implemented. The Game Screen returns the value of the current level if it was beat. Here it would return NSInteger *levelBeat = 5;

To update the array could I just do this?
Code:
[EasyMode replaceObjectAtIndex:levelBeat withObject:[NSNumber numberWithInt:1]];
So when I'm reading from the array loaded from the plist at ViewDidLoad can I use a loop to read each value to update the level screen state? Something along the lines of...
Code:
	NSString *filePath = [self pathOfFile];
	if ([[NSFileManager defaultManager]fileExistsAtPath:filePath])
	{
             NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
	     for(int LevelToUpdate = 0; LevelToUpdate < 49; LevelToUpdate++)
              { 
		NSNumber *levelStateValue = [array objectAtIndex:LevelToUpdate];       // levelStateValue is either 8 or 1 for this example
                // Here I implement whatever I need to indicate that level has been beat based on its levelStateValue 
	      }
        }

Sorry, I know these are a lot of questions but this is the only major roadblock left in my project >_<
Falimond is offline   Reply With Quote
Old 09-07-2011, 04:05 PM   #4 (permalink)
Registered Member
 
Join Date: Jul 2011
Posts: 241
MattW is on a distinguished road
Default

Well yes, of course you're going to have to initialize your NSMutableArray if you go that route, but it's no big deal. Just loop over it and add a zero number for each entry.

And yes, each entry in your NSMutableArray needs to be an NSNumber, as I showed in option 2.

Yes again: replaceObjectAtIndex() will do exactly what you want to change a value in the array.
__________________

Highlight PDF text like no other app: iHighlight (now available for iPad and iPhone!)
-----
Create iPhone lists with no typing: Insta-List
-----
Make spelling fun, and create your own tests: iWillSpell
-----
A fast, elegant flashlight app: Insta-Light
-----


FourSixteen Productions
MattW is offline   Reply With Quote
Old 09-07-2011, 06:26 PM   #5 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 16
Falimond is on a distinguished road
Default

Thanks again...it seems like for every question that's answered a bunch more pop up

The Level Select Screen isn't my main screen. And I noticed that the data saving code I posted earlier saves upon applicationWillTerminate but the user may not be on the Level Select Screen when terminating the app so I can't have it there.

So I need to be able to load and save data whenever Level Select Screen loads. Which I can do in viewDidLoad. That way if the user has beat a level, the Level Select Screen automatically appears, and the levelModeArray is updated in the plist.

Is there a way to implement all the data saving methods in viewDidLoad? Here's what I think could be done :/ I took a wild guess at changing the notification portion

Code:
LevelSelectView.m

-(NSString *)pathOfFile
{
	NSArray *path = NSSearchPathForDirectoriesInDomain(NSDocumentDirectory, NSUserDomainMask, YES); 
        // I'm getting this warning:<implicit declaration of function 'NSSearchPathForDirectoriesInDomain'>

	NSString *documentFolder = [path objectAtIndex:0];
	return [documentFolder stringByAppendingFormat:@"myfile.plist"];	
}

//Notice that the applicationWillTerminate code is gone and moved to viewDidLoad

-(void) viewDidLoad:(NSNotification*)notification       //This is probably wrong
{
	NSString *filePath = [self pathOfFile];

	if ([[NSFileManager defaultManager]fileExistsAtPath:filePath])
	{
		NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
	
		if(difficultyFlag == 0)
		{	
			NSMutableArray *tempLevelArray =  [NSMutableArray arrayWithArray:[array objectAtIndex:0]];
                        //objectAtIndex 0 since EasyModeArray was stored here previously
                }
		else if(difficultyFlag == 1)
		{
			NSMutableArray *tempLevelArray =  [NSMutableArray arrayWithArray:[array objectAtIndex:1]];
                        //objectAtIndex 1 since HardModeArray was stored here previously
		}
		else if(difficultyFlag == 2)
		{
			NSMutableArray *tempLevelArray =  [NSMutableArray arrayWithArray:[array objectAtIndex:2]];
                        //objectAtIndex 2 since ExpertModeArray was stored here previously
		}
		[array release];

               // This would check whether Level Screen View was loaded by the Game Screen and it passed a WIN
               // in that case I need to update tempLevelArray accordingly where LevelNumber is the level that was beat
               if(winFlag == 1)
               {
                 NSNumber *levelBeat = 1;
                 [tempLevelArray replaceObjectAtIndex:LevelNumber withObject:levelBeat]; // Is this the correct way to replace an object in tempLevelArray?
                }

               //This is taken from the deleted applicationWillTerminate method 
                NSMutableArray *array = [[NSMutableArray alloc] init];
               [array replaceObjectAtIndex:difficultyFlag withObject:tempLevelArray];   
               [array writeToFile:[self pathOfFile] atomically:YES];
               [array release];

                //Here I'd update the level images accordingly
                //
                //
	}

         else    //This is the first time opening the app, I initialize each mode array and store it in plist
	{      
		NSMutableArray *EasyMode = [[NSMutableArray alloc] initWithCapacity:48];
		for(int i = 0;i < 49;i++)
		{ 
			[EasyMode addObject:[NSNumber numberWithInt:0]]; 
		}
                NSMutableArray *HardMode = [[NSMutableArray alloc]  initWithCapacity:48];
		for(int i = 0;i < 49;i++)
		{ 
			[HardMode addObject:[NSNumber numberWithInt:0]]; 
		}
		
		NSMutableArray *ExpertMode = [[NSMutableArray alloc]  initWithCapacity:48];
		for(int i = 0;i < 49;i++)
		{ 
			[ExpertMode addObject:[NSNumber numberWithInt:0]]; 
		}
		
                NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:3];
                [array addObject:EasyMode];   
                [array addObject:HardMode]; 
                [array addObject:ExpertMode]; 
                [array writeToFile:[self pathOfFile] atomically:YES];
	        [array release];
	}

//This is my attempt at changing the Notification portion for viewDidLoad implementation, I doubt it's correct and I'm not sure where it's supposed to go

UIApplication *app = [UIApplication sharedApplication]; 
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(viewDidLoad:) name:UIApplicationViewDidLoadNotification object:app];

}

Just so you get a clear sense of how the critical parts of the app work, imagine that the user has already beat EasyLevels{1,2,3,4,5}, HardLevels{1,2,3}, and none of the ExpertLevels.

The app opens to a menu screen with two buttons. The first button goes to the Level Select screen, and the second button changes the difficultyFlag.

If the difficulty is set to Easy and the user hits the first button they see 48 squares. 1,2,3,4 and 5 are black (because they've been beat) and the rest are white.
If they return to the menu and change the difficulty to Hard and then hit the first button on the menu screen, they see 48 squares. 1,2 and 3 are black and the rest are white.
Same goes for expert difficulty.

Pressing one of these squares loads the actual "game board" with that level's presets.

What I'm trying to solve here is loading the correct grid of black or white squares depending on the difficulty. Hope that makes this clearer.

Last edited by Falimond; 09-07-2011 at 06:40 PM.
Falimond is offline   Reply With Quote
Old 09-07-2011, 07:41 PM   #6 (permalink)
Registered Member
 
Join Date: Jul 2011
Posts: 241
MattW is on a distinguished road
Default

Why are you trying to debug your new code via a forum? Just try it and see what happens!
__________________

Highlight PDF text like no other app: iHighlight (now available for iPad and iPhone!)
-----
Create iPhone lists with no typing: Insta-List
-----
Make spelling fun, and create your own tests: iWillSpell
-----
A fast, elegant flashlight app: Insta-Light
-----


FourSixteen Productions
MattW is offline   Reply With Quote
Old 09-08-2011, 03:45 AM   #7 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 16
Falimond is on a distinguished road
Default

Err sorry, you're right. I'm just stressed out because I've put a lot of work into this game and this saving to the plist stuff is all new to me.
I've made some alterations and might have something that works.

I do have another question.
In attempting to make LevelView.m and GameView.m communicate with each other I've managed to pass data from LevelView.m to GameView.m in this format.

LevelView.m
Code:
#import "LevelView.h"
#import "GameView.h"
@synthesize winFlag;

-(IBAction)goToGameView
{
	GameView *gameView = [[GameView alloc] initWithNibName:@"GameView" bundle:nil];
	gameView.levelNumber = LevelSelectedValue;
	gameView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
	[self presentModalViewController:boardViewScreen animated:YES];
}
But to pass data from GameView.m to LevelView.m

GameView.m
Code:
#import "GameView.h"
#import "LevelView.h"
@synthesize levelNumber;

-(IBAction)goToLevelView
{	
	LevelView *levelView = [[LevelView alloc] initWithNibName:@"LevelView" bundle:nil];
	levelView.winFlag = winFlagValue;
	[self dismissModalViewControllerAnimated: YES];
	 
}
upon running the program, levelNumber is passed from LevelView to GameView but winFlag isn't passed from GameView to LevelView.

This might have to do with cyclic dependencies but if it does then I don't understand why the first transfer happens but the second does not. Any suggestions on passing integers both ways between these views?
Falimond is offline   Reply With Quote
Old 09-08-2011, 11:18 AM   #8 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by MattW View Post
Why are you trying to debug your new code via a forum? Just try it and see what happens!
Why work if suckers like us will do the work for him?
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 09-08-2011, 11:33 AM   #9 (permalink)
Registered Member
 
Join Date: Jul 2011
Posts: 241
MattW is on a distinguished road
Default

LOL!
__________________

Highlight PDF text like no other app: iHighlight (now available for iPad and iPhone!)
-----
Create iPhone lists with no typing: Insta-List
-----
Make spelling fun, and create your own tests: iWillSpell
-----
A fast, elegant flashlight app: Insta-Light
-----


FourSixteen Productions
MattW is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 372
8 members and 364 guests
apatsufas, JackReidy, jeroenkeij, Sami Gh, tim0504, UMAD, yomo710
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,671
Threads: 94,121
Posts: 402,904
Top Poster: BrianSlick (7,990)
Welcome to our newest member, JackReidy
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 04:54 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0