When is a GKGameCenterViewController released? - ios

The following documentation has the sample code below:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/LeaderBoards/LeaderBoards.html#//apple_ref/doc/uid/TP40008304-CH6-SW9
Listing 4-9 Displaying the leaderboard page of the Game Center user
interface
- (void) showLeaderboard: (NSString*) leaderboardID
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil)
{
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterController.leaderboardTimeScope = GKLeaderboardTimeScopeToday;
gameCenterController.leaderboardCategory = leaderboardID;
[self presentViewController: gameCenterController animated: YES completion:nil];
}
}
When do you call "release" on the GKGameCenterViewController ? Should it be only after the view controller is dismissed, or can you call it at the end of this method ? Or should one just call autorelease ?

The project uses Automatic Reference Counting, therefore you do not need to explicitly declare release or dealloc. For reference, it is deallocated after the view leaves the view hierarchy.

I can't find any documentation to back this up (because all of Apple's documentation now assumes ARC), but my recollection from the pre-ARC days is that you release a modal view controller once you present it. I'm reasonably sure the presenting view controller will take a strong reference to the presented view controller. So:
- (void) showLeaderboard: (NSString*) leaderboardID
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil)
{
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterController.leaderboardTimeScope = GKLeaderboardTimeScopeToday;
gameCenterController.leaderboardCategory = leaderboardID;
[self presentViewController: gameCenterController animated: YES completion:nil];
[gameCenterController release];
}
}
A better answer might be, "use ARC". :) Seriously, ARC rules.

Related

Cannot dismiss GKGameCenterViewController presented from SKScene

I'm presenting a GKGameCenterViewController from an SKScene. This is my code:
-(void)showLeaderboardAndAchievements:(BOOL)shouldShowLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = _leaderboardIdentifier;
// _spriteViewController references an UIViewController
[_spriteViewController presentViewController:gcViewController animated:YES completion:nil];
}
I don't have problems presenting the window, however I cannot manage to let users close it. I implemented the method gameCenterViewControllerDidFinish however the function is not called at all. What do I have to do so users can close the leaderboard?
I fixed by adding the line gcViewController.gameCenterDelegate = _spriteViewController;
-(void)showLeaderboardAndAchievements:(BOOL)shouldShowLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = _leaderboardIdentifier;
gcViewController.gameCenterDelegate = _spriteViewController; // er
// _spriteViewController references an UIViewController
[_spriteViewController presentViewController:gcViewController animated:YES completion:nil];
}
While it worked I got the warning:
Assigning to 'id<GKGameCenterControllerDelegate>' from incompatible type 'UIViewController *__weak'
For anyone in this situation the problem was simply that _spriteViewController was of typeUIViewController, changing that to my custom class fixed the issue. You can also declare the property referencing the ViewController like this:
UIViewController <GKGameCenterControllerDelegate> *_spriteViewController;

How to pull up a Gamecenter leaderboard with a button?

I am trying to use the button to pull up a single view Gamecenter leaderboard and cant really figure out how. I tried apples forums but didnt help so I came here. Help is appreciated
The view controller that will present the GKGameCenterViewController must conform to the <GKGameCenterControllerDelegate> protocol.
To present the leaderboard:
GKGameCenterViewController *leaderboardController = [[GKGameCenterViewController alloc] init];
if (leaderboardController != NULL) {
leaderboardController.gameCenterDelegate = self;
[self presentViewController:leaderboardController animated:YES completion:nil];
}

Apple's controllers not presenting properly in iOS7

In my iOS app i present standerd controllers MFMessageComposeViewController and UIImagePickerController.
But they both presenting with strange navigation bar.
How can i fix this problem?
UPD code for presenting controllers
UIImagePickerController:
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = sourceType;
cameraUI.allowsEditing = YES;
cameraUI.delegate = self;
[self presentViewController:cameraUI animated:YES completion:nil];
MFMessageComposeViewController:
MFMessageComposeViewController *messageViewController = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText]) {
messageViewController.view.backgroundColor = [UIColor whiteColor];
messageViewController.messageComposeDelegate = self;
recipient= [NSStringMask maskString:recipient withPattern:#"\\+(\\d{1}) \\((\\d{3})\\) (\\d{3})-(\\d{2})-(\\d{2})"];
messageViewController.recipients = #[recipient];
messageViewController.body = body;
[self presentViewController:messageViewController animated:YES completion:nil];
}
In iOS 7, the status bar and the navigation is translucent by default. To make the view act 'normal' like in iOS 6. you need to add this to the controller you are presenting.
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
If you want to read up more about changes in views. Check out this post. I find it a nice quick overview whats changed.
http://www.brianjcoleman.com/ios7-weve-got-a-problem/
See this question. I used the second answer, though I suspect the first would work for me also.

GKGameCenterViewController always shows Challenges instead of Leaderboards

I'm using Apple's code to show a GKGameCenterViewController:
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
This is the text describing the code above:
Game Center UI is Displayed by Your View Controller (iOS)
The convention used by Game Kit is for one of your view controllers to present the Game Kit view controller. Your view controller acts as a delegate to the view controller it presents so that it can be informed when the player is finished looking at the presented screen. Listing 2-1 shows most common use of this pattern, which is to show the Game Center user interface. The Game Center view controller displays many different pieces of Game Center content, so most games should offer a button that brings the player to this screen, even if the game also shows Game Center content using a custom user interface.
When I use the recommended code I get to this screen (GameCenter Challenges), which is not what I want:
I have also tried this code:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"gamecenter:"]];
By using that code, I get to the screen I expected to display:
Do I misunderstand something or am I doing something wrong? Shouldn't the first piece of code bring me to the main menu? Why won't it show the leaderboards?
UPDATE
I implemented viewState as suggested by phix23:
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
But, it still displays the same Challenges screen, despite the fact that I want /try to display the Leaderboards screen.
The GKGameCenterViewController which is available since iOS 6 can show the leaderboards, achievements and challenges of your game center enabled application.
You can change the initial view by setting the viewState of the GKGameCenterViewController. If you don't set this property it will show the default view, which is the challenges view in your case. I guess you don't have setup any leaderboards or achievements so there is nothing to be shown.
Try using this code:
-(void)showGameCentersDefaultPage {
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateDefault;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
}
If you want to begin with a specific type of GameCenter Leaderboard you can call the following method with your leaderboardID
- (void)showLeaderboard:(NSString*)leaderboardID {
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
//The next three lines are the lines of interest...
gameCenterController.viewState = GKGameCenterViewControllerStateDefault;
gameCenterController.leaderboardTimeScope = GKLeaderboardTimeScopeToday;
gameCenterController.leaderboardCategory = leaderboardID;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
}
For iOS 7.0, I use the following:
Display Leaderboard:
- (void)displayLeaderboard:(UIViewController *)viewController
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
[viewController presentViewController:gameCenterController animated:YES completion:nil];
}
}
Display Achievements:
- (void)displayAchievements:(UIViewController *)viewController
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateAchievements;
[viewController presentViewController:gameCenterController animated:YES completion:nil];
}
}
Note that the view controller trying to use these functions will need to pass itself (i.e. viewController param must be set to some active view controller).
Hope this helps.
Use GKGameCenterViewController and set the view state:
//Create a leaderboard view controller
GKGameCenterViewController *leaderboardViewController = [[GKLeaderboardViewController alloc] init];
leaderboardViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
//Set the time scope (ex. All Time, This Week, Today) and the leaderboard ID
leaderboardViewController.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardViewController.leaderboardCategory = leaderboardID;
//Set the delegate so we can handle various actions including dismissal
leaderboardViewController.leaderboardDelegate = self;
//Present the view controller
[self presentViewController:leaderboardViewController animated:YES completion:nil];
This code will present a view controller that displays all of your games leaderboards (or the rankings if there is only one). You can also set properties such as which leaderboard to show, the time scope, delegate, etc. Also note that you can do a similar thing with achievements using the GKAchievementViewController.
The code that you provided in your question,
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"gamecenter:"]];
Launches the GameCenter app. This means that iOS will exit your app and switch to GameCenter. This could be confusing to the user. You should also avoid making the user leave your app. Instead, use the GKViewControllers which are presented modally inside of your app.

Presenting view not appearing properly after MFMessageComposeViewController is presented and then dismissed

I have a View Controller which displays a table view. The VC calls another VC to display the send SMS view to the user, the code for this SMS VC is:
- (void) sendSMSWithBody: (NSString*) body andRecipients: (NSArray*) recipients
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText])
{
controller.messageComposeDelegate = self;
controller.body = body;
controller.recipients = recipients;
[[UIApplication sharedApplication].delegate.window.rootViewController addChildViewController:self];
[self presentModalViewController:controller animated:YES];
}
}
- (void) messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication].delegate.window.rootViewController removeFromParentViewController];
}
(I know the call to sharedApplication is a bit hacky, but it will suffice for now. the rootViewController is a UINavigationController which has its root controller set to the table view controller)
I am invoking the SMS VC from the table VC like so:
- (void ) viewDidAppear:(BOOL)animated
{
static BOOL presentedSMSVC = NO;
if (!presentedSMSVC)
{
SendSMSController *sendSMS = [[SendSMSController alloc] init];
[sendSMS sendSMSWithBody:#"body"
andRecipients:[NSArray arrayWithObject:#"123456789"]];
presentedRegisterVC = YES;
}
}
The problem is that after the user sends the SMS the table view cells are not displaying.
I thought maybe I need to refresh the view/table so I added a protocol callback from the 2nd VC to the first which gets invoked when the user sends the SMS, and then within the callback call [self.tableView reloadData] But it made no difference.
So I got rid of the intermediary class and edited the table view to display the SMS view directly like this:
- (void ) viewDidAppear:(BOOL)animated
{
static BOOL presentedRegisterVC = NO;
if (!presentedRegisterVC)
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText])
{
controller.messageComposeDelegate = self;
controller.body = #"body";
controller.recipients = [NSArray arrayWithObject:#"12345678"];
[self presentModalViewController:controller animated:NO];
}
}
}
- (void) messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:NO];
}
But now the MFMessageComposeViewController doesn't dismiss (although messageComposeViewController:didFinishWithResult: does get called)
What is the problem with both approaches? Thanks
For the second variant, I changed to:
[self presentViewController: controller animated: YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
And that worked, haven't tried applying to the first method.
I faced a similar UI issue.
My case was: The controller, let's say controller A, in which I had written the code to present and dismiss the MFMessageComposeController, was not being used directly as the active controller rather I was using A.view as a subview over another controller, say controller B. So writing the following was distorting the view:
[self presentViewController:composeVC animated:YES completion:nil];
But then writing the following solved my issue:
[self.customTabbarNavigation presentViewController:composeVC animated:YES completion:nil];
The customTabbarNavigation, was the controller B, ans was actually the navigation controller which was active when controller A's view was visible.
Same change had to be made for dismissing the composeVC.

Resources