endTurnWithNextParticipant deprecation - iphone

Thought I fixt my problem with the deprecation, I now found out I haven't. My game is not functioning correctly.
In the new endTurnWithNextParticipant there is also a timeout for the next player (the timeinterval they have to answer on there turn) I have set that on 86400 (seconds in a day)
However the game doesn't send a turn at all anymore, I can set the second to for example 1 then it would send the turn but still later then it used to before the deprecation. even If I set the interval to 0.
I think the problem is that the turn is send to the player that has just send a turn.
this is the code: (the commented line is the what I used but is now deprecated)
[currentMatch endTurnWithNextParticipants:currentMatch.participants turnTimeout:86400 matchData:data completionHandler:^(NSError *error){
//[currentMatch endTurnWithNextParticipant:nextParticipant matchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
statusLabel.text = #"Oops, there was a problem. Try that again.";
} else {
statusLabel.text = #"Your turn is over.";
textInputField.enabled = NO;
}
}];
I hope someone can help me out.

Instead of currentMatch.participants, you may want to try
[[NSArray alloc] initWithObjects:nextParticipant,nil]
That way, the only player that's being sent is nextParticipant, the same way you had it in the deprecated code.

Related

How to get local player score from Game Center

How to get score of local player from Leaderboard Game Center? I tried this code, but it returns nothing. Anybody know how to solve it, or is there better way how to get score?
- (NSString*) getScore: (NSString*) leaderboardID
{
__block NSString *score;
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.identifier = leaderboardID;
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil)
{
int64_t scoreInt = leaderboardRequest.localPlayerScore.value;
score = [NSString stringWithFormat:#"%lld", scoreInt];
}
}];
}
return score;
}
I think, that method have to wait for completion of [leaderboardRequest loadScoresWithCompletionHandler: ...
Is it possible?
Your code appears to not have any bugs that I can see. I would recommend displaying the standard leaderboard interface to see if your code that reports the scores is actually working correctly. If so, you should see the scores in the leaderboard. The code below works in my game, and I know the score reporting is working properly because it shows in the default game center UI.
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
leaderboardRequest.identifier = kLeaderboardCoinsEarnedID;
[leaderboardRequest loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else if (scores) {
GKScore *localPlayerScore = leaderboardRequest.localPlayerScore;
CCLOG(#"Local player's score: %lld", localPlayerScore.value);
}
}];
If you aren't sure how, the code below should work to show the default leaderboard (iOS7):
GKGameCenterViewController *gameCenterVC = [[GKGameCenterViewController alloc] init];
gameCenterVC.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterVC.gameCenterDelegate = self;
[self presentViewController:gameCenterVC animated:YES completion:^{
// Code
}];
You cannot return score outside the block. In this code first "return score" will be executed before the method "loadScoresWithCompletionHandler". Additionally you haven't set initial value for "score", this method will return completely random value.
I suggest you to put your appropriate code inside the block, instead of:
int64_t scoreInt = leaderboardRequest.localPlayerScore.value;
score = [NSString stringWithFormat:#"%lld", scoreInt];
The leaderboard request completes after the return of your method. This means that you are returning a null string.
The method you put the leaderboard request in should be purely for sending the request. The method will be finished executing before the leaderboard request is complete thus your "score = [NSString stringWithFormat:#"%lld", scoreInt];" line is being executed AFTER the return of the "score" which is null until that line is executed.
The solution is to not return the outcome of the completion handler using the method that sends the request. The score is definitely being retrieved correctly, so just do whatever you need to with the score inside of the completion handler. You have no way to know when the completion handler is going to be executed. This, in fact, is the reason why Apple allows you to store the code to be executed in a block! Although, it can be confusing to understand how to work with blocks that will definitely be executed later, or in your situation, sometime after the method is returning.
The best way to handle your situation is to not return anything in this method and just use the "score" variable as you intend to after the block has set score to a non-null value!

GKTurnBasedMatch match-making waiting until another player matched

I find the default turn based matchmaking process unintuitive for users. The matchmaker returns a match even when the other player is not yet found and then local user has to take turn in a fresh game after which he/she has to wait in game screen. Instead of that I would rather have the users stay in an interactive screen where they can cancel their match request or wait until they are matched (then I decide who starts first). Is there any way to do this, not a workaround but a robust one?
My current code, doing nothing towards my purpose, is below:
-(IBAction)gcMatchPressed:(id)sender
{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playerGroup = PLAYERGROUP;
[GKTurnBasedMatch findMatchForRequest:request withCompletionHandler:^(GKTurnBasedMatch *match, NSError *error) {
if (match != nil)
{
self.gcMatch = match;
[self performSegueWithIdentifier:#"Multiplayer" sender:self];
}
} ];
}

iOS 6 SDK SLRequest returning '400'

Let me make this clear. I am NOT using the Facebook SDK. I'm using iOS SDK's Social.framework, and ACAccountStore to access Facebook accounts, and post with it/them.
I use the same code to post on Twitter. It works 100%. But for some reason regardless of what I do for Facebook integration, I get a "400" error when I try to post.
My method is:
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *facebookAccountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
// Specify App ID and permissions
NSDictionary *options = #{ ACFacebookAppIdKey: #"MY_APP_ID",ACFacebookPermissionsKey: #[#"publish_stream", #"publish_actions"],ACFacebookAudienceKey: ACFacebookAudienceFriends };
[account requestAccessToAccountsWithType:facebookAccountType options:options
completion:^(BOOL granted, NSError *error)
{
if (granted == YES)
{
NSDictionary *parameters = #{#"message": string999};
NSURL *feedURL = [NSURL URLWithString:#"https://graph.facebook.com/me/feed"];
SLRequest *feedRequest = [SLRequest
requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodPOST
URL:feedURL
parameters:parameters];
acct.accountType = facebookAccountType;
// Post the request
[feedRequest setAccount:acct];
// Block handler to manage the response
[feedRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if (granted && error == nil) {
} else {
NSLog(#"Facebook response, HTTP response: %i %#", [urlResponse statusCode], [error description]);
[self closeShareMenu];
}
}];
}
}
I don't know where I'm going wrong! It's so annoying! I've set up my app correctly in Facebook Developers and all! Please help -_-'
Following up to the chat session held between #fguchelaar and yours truly yesterday; I was able to ascertain the following solution for this issue.
Add the following in your iOS completion handler:
NSString *temp = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];
NSLog(temp);
//'data' is your 'responseData' (or another object name) that you declare in your completion handler.
This will allow you to see the exact cause of the issue printed to the Debug Console. Now depending on the issue presented, you'll need to grab a Facebook account from the Array of Accounts generated when you call this handler in the iPhone SDK. Not at any prior stage whatsoever, as the Access Token will likely expire and give you this '400' error.
In my case; the error printed was: error:{'400' A valid access token is required… which vastly annoyed me as my prior method to access and check the current Twitter account was working perfectly. And my theory was that it should work just as well for Facebook. Why should the access token be instantaneously revoked if I'm grabbing the account a split second before?
The way I solved my issue (depending on the reason for your error the answer can vary) was to use a for loop to check the newly created array of accounts, with the sole purpose of finding the account there with the same identifier string as the one I saved into NSData/NSKeyedArchiver.
for(ACAccount *a in arrayOfAccounts) {
if([a.identifier isEqualToString:storedAccount.identifier]) {
//set the account to be used
accountToBeUsed = a;
//don't forget to break the For loop once you have your result.
break;
} else {
//This else{} block is not strictly necessary, but here you could set an account if no account was found with a matching identifier.
}
}
For it to work, it's recommended to declare an ACAccount object in your View Controller's .h file, add a #property and #synthesize it, so it can be assigned within the for loop and used after the break; statement.
This effectively solved my whole issue with the '400' error. It was inexplicably frustrating for about six hours of my day, so I hope that my explanation helps anybody who happens to stumble across this issue, and my question here on Stack Overflow :)
Regards,
cocotutch

iOS Test Connectivity to the Server During App Lanuching Takes Too Long

I have an app that allow automatic login for a user. What my boss want is, when the app launches, the app need to test connectivity to our server (not just test whether there is WiFi or 3G network). I borrowed apple's Reachability sample, it works.
A problem is that takes too long, especially at the launch time. I tried it on a local wireless network without internet connection, it took me almost half an minute to do so. And since auto login called in -ViewDidLoad(), for that half minute, ui didn't load. It is just simply not acceptable to take the time that long. What's even worse, if my app takes too long to load, iOS might even shut the app down.
Further more, I have a lot of web service calls in my app. I understand each web service call could have the chance to fail, because the nature that iPhone/iPad can lose or gain connection easily even when user talk a short walk from one place to another. I personally don't like it but that's what my boss want me to do, and I probably have to test the connection quite often in the app.
So here what I am looking for is either a way to detect connection really really fast(within seconds) or a way to do it behind the scenes and not effect user experience.
Anybody has suggestions?
Thank you for taking your time reading my questions.
Present an intermediate loading view with presentModalViewController while the test is taking place and run the actual test using performSelectorInBackground. Then signal back to the main thread with performSelectorOnMainThread:
- (void)viewDidLoad
{
[super viewDidLoad];
// Make this a hidden member
loadingViewController = [LoadingViewController new];
[self presentModalViewController:loadingViewController animated:NO];
[self performSelectorInBackground:#selector(testConnectivity) withObject:nil];
}
- (void)testConnectivity
{
// Do expensive testing stuff
[self performSelectorOnMainThread:#selector(testCompleted) withObject:nil waitUntilDone:NO];
}
- (void)testCompleted
{
[loadingViewController dismissViewControllerAnimated:YES];
loadingViewController = nil;
}
Note that the overall user experience of waiting 30 seconds for the application to start sort of sucks, and connectivity often changing while you are using an app, so even if you do the test every startup it's unlikely to be reliable. But if it is what your boss wants I suffer with you. ;)
For what it's worth, here is the method I use..
- (BOOL)checkServerAvailability {
bool success = false;
const char *host_name = [#"host" cStringUsingEncoding:NSASCIIStringEncoding];
SCNetworkReachabilityRef reachability =
SCNetworkReachabilityCreateWithName(NULL, host_name);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
bool isAvailable = success && (flags & kSCNetworkFlagsReachable)
&& !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
return isAvailable;
}
Here is the logging result of my server check method...
2012-07-11 11:29:04.892 ASURecycles[1509:f803] starting server check...
2012-07-11 11:29:04.894 ASURecycles[1509:f803] creating reachability...
2012-07-11 11:29:04.894 ASURecycles[1509:f803] creating flags...
2012-07-11 11:29:04.913 ASURecycles[1509:f803] checking for success of reachability, assigning to flags..
2012-07-11 11:29:04.913 ASURecycles[1509:f803] checking our flags to determine network status...
2012-07-11 11:29:04.913 ASURecycles[1509:f803] not available
As you can see, fractions of a second. Of course our server is undergoing trouble at the moment, but I think your issue may be a server issue, not a framework issue. You could always try executing the server check on another thread though.
As I told in the comments you should use Hampus Nilsson's approach to perform the request in the background anyways.
Regarding to your 30 seconds problem I found this in another blog:
- (BOOL)isHostAvailable:(NSString*)hostName
{
// this should check the host but does not work in the simulator, aka it returns YES when should be no
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName cStringUsingEncoding:NSASCIIStringEncoding]);
SCNetworkReachabilityFlags flags;
BOOL success = SCNetworkReachabilityGetFlags(reachability, &flags);
if (reachability) {
CFRelease(reachability);
}
if ( ( success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired) ) == NO) {
return NO;
}
// we know at least the network is up, second check for a known page
NSData *dataReply;
NSURLResponse *response;
NSError *error;
// create the request
NSString *urlString = [NSString stringWithFormat:#"http://%#/index.php", hostName];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:8.0];
// Make the connection
dataReply = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
if (response != nil) {
NSLog(#"SNNetworkController.isHostAvailable %#", response);
return YES;
} else {
// inform the user that the download could not be made
NSLog(#"SNNetworkController.isHostAvailable %# %#", response, error);
return NO;
}
}
this will perform a request with a timeout value of 8 seconds.
//EDIT:
ASIHTTPRequest example:
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setNumberOfTimesToRetryOnTimeout:3];
[request setTimeOutSeconds:20.0];
[request setRequestMethod:#"POST"];
[request startAsynchronous];

Server error when trying to report Achievement to GameCenter

When using the code from Apple,
- (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
{
GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
if (achievement)
{
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
NSLog(#"problem with reporting");
NSLog(#"%#",[error localizedDescription]);
// Retain the achievement object and try again later (not shown).
}
}];
}
}
I get the error:
The requested operation could not be completed due to an error communicating with the server.
I have verified the user and it seems to register that i have played the game, but it cannot record the achievement. Any ideas?
Try using the reachability sample application from Apple to find out if the iPhone is connected to the internet via wifi or 3G. http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html
It takes a few minutes for the Achievements from itunesconnect to propagate to the server.
Just try a little later, and it will not hurt to deinstall and install app again either.