saving data in iPhone development - iphone

I have some unsolved problem right now. My game is done, now I am at the last stage. In the main menu of the game there will be a button called goodies. Only appears when the user win the game once. I can do until that part . But the last part is to save that goodies. Meaning when the player exist the game after he able to make the button appear, the button still there when he gets back to the game? Could you guys help me out I am not quite sure how to do it. I heard a lot about NSUSerDefault, but don know how it works and how to apply it properly. Thanks for any help.
DegrafeurAppDelegate *appdelegate = (DegrafeurAppDelegate *) [[UIApplication sharedApplication] delegate];
//BOOL b = appdelegate.checkStatus;
if(appdelegate.checkStatus == YES)
{
[goodies setVisible:YES];
}
else
{
[goodies setVisible:NO];
}
This is my code to enable the button after winning once. But how to save it, please help me

As you mentioned, you can user NSUserDefaults:
NSUserDefaults myPrefs = [[NSUserDefaults alloc] init];
[myPrefs setBool:YES forKey:#"displayed_win_button"];
[myPrefs release];
and later to check the value:
if([myPrefs boolForKey:#"displayed_win_button"]) { ... }

Related

Is MPNowPlayingInfoCenter compatible with AVAudioPlayer?

I start -play with AVAudioPlayer, and then set the nowPlaying dictionary like this:
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
        
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imagedNamed:#"AlbumArt"]];
[songInfo setObject:#"Audio Title" forKey:MPMediaItemPropertyTitle];
[songInfo setObject:#"Audio Author" forKey:MPMediaItemPropertyArtist];
[songInfo setObject:#"Audio Album" forKey:MPMediaItemPropertyAlbumTitle];
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
The lock screen always shows a pause button. I receive the remote control events correctly and I can toggle play/pause through the remote control events, but the lock screen keeps showing "pause" even when it is playing.
Now I seen this work with MPMoviePlayerController. Can someone explain how does the MPNowPlayingInfoCenter determine if it should show a play or a pause button?
Have you set the correct AVAudioSessionCategory on the AudioSession? it needs to be AVAudioSessionCategoryPlayback I believe to get it to work.
I'm not using MPNowPlaying at the moment, but apparently I have to, in order to get the audio info displayed on the lock screen.
However, in addition to what #user3061915 said, to manage the play/pause button, I've used UIEventTypeRemoteControl and it works perfect for controlling the play/pause button:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl)
{
if (event.subtype == UIEventSubtypeRemoteControlPlay)
{
[self playAudio];
}
else if (event.subtype == UIEventSubtypeRemoteControlPause)
{
[self pauseAudio];
}
else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause)
{
[self togglePlayPause]; //This method will handle the toggling.
}
}
I just fixed a problem like this in my own app. I originally used [[AVAudioSession sharedInstance] setCategory:withOptions:error:] and supplied AVAudioSessionCategoryOptionMixWithOthers and AVAudioSessionCategoryOptionDuckOthers. This turned out to be my problem. If you set mix with others, you get no remote control events. They still go to the iPod app. If you set duck others, you get remote control events, but it appears as though it causes the problem you describe: the play/pause button shows the wrong thing. I'm not sure why. I got the play/pause button to behave by setting options to 0, or actually just calling setCategory:error:.

Real Time Game Center game disconnects (possibly because of network timeout)

So, I'm writing a very simple real time game center 2-player game; however, the problem is I keep getting disconnected.
The game works as follows: Each player has a text field on their device. They each enter text in the field and press enter. When both people have inputted text, the game progresses.
Now, when the users are actively playing the game (inputting text every 10 seconds or so), the game works just fine and a user has never been disconnected. However, when the game remains inactive (the user just sits and stares at the app screen) for about 30 seconds or more, at least one player gets disconnected.
I'm pretty confident that my Internet is solid and both devices appear to be connected to the Internet (via wifi).
I know this is a very vague question, I was just wondering if anyone has any ideas related to the symptoms in bold above.
EDIT:
Here's how I initialize the matchrequest and the match. However, I'm having no trouble initializing or starting the match. The only problem is when a player goes idle for some length of time
//toInvite may be nil
- (void) createMatchWithPlayersToInvite: (NSArray *) toInvite
{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = toInvite;
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithMatchRequest:request];
self.myMatchmakerVC = mmvc;
mmvc.hosted = NO;
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];
}
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match
{
[self dismissViewControllerAnimated:YES completion:nil];
self.myMatch = match;
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.currentMatch = self.myMatch;
if (!self.matchStarted && match.expectedPlayerCount == 0)
{
self.matchStarted = YES;
[self performSegueWithIdentifier:#"gameSegue" sender:self];
}
}
EDIT 2:
So, I've discovered that if I set a timer and send messages across the network (with [self.myMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error]) every 1 second, the program works just fine. Does anyone have idea why this is or how I can fix my issue without resorting to a hacked together NSTimer?
Other notes:
1) My AppDelegate has not been changed
Looks like you have a clear hypothesis here, i.e. that Game Center connections are closed after 30 seconds idle time. I would not be surprised if this is the case. Other games almost certainly will send data within such an interval, and you may be triggering a timeout condition. To test this hypothesis and fix the problem at the same time, I would send a short blind text every five or ten seconds.

iPhone GameCenter won't showAchievments

So my problem is that after integrating gamecenter nicely into my iphone app, it won't show the achievements list!
The integration was a success I think because when I use the submitAchievement method, I do unlock achievements on the list. But I must look at the list from the GameCenter App on the iPhone, not within my own app as it doesn't work.
ikuragames first help me get the code right (thx you !!) but it still doesn't work ! :(
-(void)showAchievments
{
//NSLog(#"showAchievments");
GKAchievementViewController *achievements = [GKAchievementViewController alloc] init];
if (achievements != nil)
{
achievements.achievementDelegate = self;
[(EAGLView *)self.view achievmentsWillAppear];
[self presentModalViewController:achievements animated:YES];
}
}
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
//NSLog(#"achievementViewControllerDidFinish");
[glView achievmentsWillDisappear];
[self dismissModalViewControllerAnimated:YES];
}
On debug mode, I can clearly see that each line or code are "processed" and not error whatsoever is displayed. BUT, nothing appears on my screen :(
Can you please help me ? (here is some doc.)
I found the answer.
Turned out that the view controller I was sending showAchievments to was not the view controller I wanted.
I was doing something like:
[[myViewController sharedInstance] showAchievments];
But the sharedInstance method returned a brand-new, vanilla-initialised myViewController, and not the one I was already using.
Now it works perfectly, I hope this will help someone in the future.

Detect when GameCenter UI is displayed

I'm trying to integrate my game with Game Center and encountered this problem:
When user is authenticated for a first time, Game Center shows its UI for setting up the profile.
My problem is that I can not detect when this windows is shown - I want to pause my game at that moment and not play any sounds.
viewWillDisapper, viewDidDisapper in UIViewController are not called, neither are any of AppDelegate methods are called at this time.
I think I know how detect alert views (using changing key window notification), but that Account windows still is not detected there.
Is there any way to do this?
Building on executor21's answer here, I put this together which seems to do the trick in early testing. You can probably adapt it into something less fragile. It is built on the premise that the Game Center notification gets its own window, and it has exactly one subview of type GKGameEventView:
+(BOOL)isGameCenterNotificationUp
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow *win in windows)
{
NSArray *winSubViews = [win subviews];
if([winSubViews count] == 1)
{
Class gcNotificationClass = NSClassFromString(#"GKGameEventView");
if(gcNotificationClass && ([[winSubViews objectAtIndex:0] isKindOfClass:gcNotificationClass]))
{
return YES;
}
}
}
return NO;
}

UIImagepickerController [takepicture] modal view disappears no delegate callback

Update:
This has been answered. It was my own stupidity, possibly not worth reading any more of this question. lol.
Question:
Right so i have this UIViewController(master) subclass, it has a UIImagepickerController(camera), it also has a UIView(overlayView). Master setups the camera to be configured as a camera only with a custom cameraOverlay, hiding the custom controls e.t.c.
All appears to work fine apart from when i try to programatically take a picture. What happens is the overlayView calls the master and this triggers the take picture, then i hear the shutter sound and the iris closes, the camera appears to dismiss itself (i am defiantly not doing this in my code) and then my viewDidAppear gets called in my master again.
Anybody have any idea whats going on ?
-(void)viewDidLoad
{
NSLog(#"loading the view");
//if the camera is on the device
if ( [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
//make one
camera = [[UIImagePickerController alloc] init];
//setup some settings that we need
camera.sourceType = UIImagePickerControllerSourceTypeCamera;
camera.showsCameraControls = NO;
camera.navigationBarHidden = NO;
camera.toolbarHidden = YES;
camera.cameraViewTransform = CGAffineTransformScale(camera.cameraViewTransform, 1.03, 1.03);
//show it
overlayView = [[OverlayView alloc] initWithFrame:CGRectMake(0,0,320,480) withDelegate:self andController:self];
camera.cameraOverlayView = overlayView;
camerashowing=NO;
}
else
{
alert = [[UIAlertView alloc] initWithTitle:#"No Camera Detected" message:#"The camera is broken or your device has no camera. Please close the application" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
-(void)viewDidAppear:(BOOL)animated
{
if (!cameraShowing)
{
NSLog(#"going to show camera");
[self presentModalViewController:camera animated:NO];
camerashowing = YES;
}
}
-(void)releaseShutter
{
[overlayView toolbarShowWarning];
NSLog(#"going to show camera: %#", self);
[camera takePicture];
}
After some help advice from people in the answers i can say that the camera is not being released.
I have also managed to stop the exec_bad_access by stopping it from calling [presentmodal....] for a second time by checking a bool value in the viewDidAppear Method.
I still have the issue where the modal view disapears, any help, again lol ??
I think you're missing a camera.delegate = self;
For any EXC_BAD_ACCESS errors, you are usually trying to send a message to a released object. The BEST way to track these down is use NSZombieEnabled.
This works by never actually releasing an object, but by wrapping it up as a "zombie" and setting a flag inside it that says it normally would have been released. This way, if you try to access it again, it still know what it was before you made the error, and with this little bit of information, you can usually backtrack to see what the issue was.
It especially helps in background threads when the Debugger sometimes craps out on any useful information.
VERY IMPORTANT TO NOTE however, is that you need to 100% make sure this is only in your debug code and not your distribution code. Because nothing is ever released, your app will leak and leak and leak. To remind me to do this, I put this log in my appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
If you need help finding the exact line, Do a Build-and-Debug (CMD-Y) instead of a Build-and-Run (CMD-R). When the app crashes, the debugger will show you exactly which line and in combination with NSZombieEnabled, you should be able to find out exactly why.
Check the value of the camera member variable before you try and display it:
NSLog(#"going to show camera: %#", camera);
I suspect it might be being released somewhere, but as coneybeare NSZombieEnabled will let you track it down.