I'm trying to clear all my matches in Game Center, and I'm using the following code to do so:
if ([GKLocalPlayer localPlayer].authenticated == NO) {
[[GKLocalPlayer localPlayer] setAuthenticateHandler:^(UIViewController* viewcontroller, NSError *error) {
[GKTurnBasedMatch loadMatchesWithCompletionHandler: ^(NSArray *matches, NSError *error){
for (GKTurnBasedMatch *match in matches) {
NSLog(#"Match ID:%#", match.matchID);
[match removeWithCompletionHandler:^(NSError *error){
NSLog(#"%#", error);}];
}}];
}];
} else {
NSLog(#"Already authenticated!");
}
And this works for almost all my games, except a few which all have 0 participants. The description of these games is as follows:
GKTurnBasedMatch 0x17eb78b0 - matchID:2e36f8fe-5b07-4fea-9e8f-6997187f2235 bundleID:Mad-Shark-GamesTEST.Letterslide status:GKTurnBasedMatchStatusOpen message:(null) creationDate:2014-03-14 23:44:06 +0000 currentParticipant:(null) participants:(null) matchData.length:0 matchDataMaximumSize:65536 exchanges:(null)
I've seen the post on removing invalid games, but my error is not caused by an invite, and I have no participants to change the state. Unfortunately I can't remember exactly what I did to cause this error, and I've been trying to replicate it but so far no "luck". Can anyone help me figure out what could have caused this and how to clear out these games? Thank you!!
I know it's a long time since you posted the question, but today i came up to a similar situation and my solution was to "force" participantQuitOutOfTurnWithOutcome:, even if i had no participants.
[updatedMatch participantQuitOutOfTurnWithOutcome:GKTurnBasedMatchOutcomeQuit withCompletionHandler:^(NSError *error)
{
if (error)
{}
else
{}
}];
Related
In iOS 9.3 Apple release new APIs. Now developers can see if a user is currently a member of Apple Music. I'm trying to understand how it works.
My code -only first time- asks the user whether to access the music library but I don't understand how to determine in what ways you can detect if user is a member and open Apple Music to join it. These actions in Shazam works really great. How can I do something like that?
Thanks in advance!
[SKCloudServiceController requestAuthorization:^(SKCloudServiceAuthorizationStatus status) {
NSLog(#"status is %ld", (long)status);
SKCloudServiceController *cloudServiceController = [[SKCloudServiceController alloc] init];
[cloudServiceController requestCapabilitiesWithCompletionHandler:^(SKCloudServiceCapability capabilities, NSError * _Nullable error) {
NSLog(#"%lu %#", (unsigned long)capabilities, error);
if (capabilities >= SKCloudServiceCapabilityAddToCloudMusicLibrary || capabilities==SKCloudServiceCapabilityMusicCatalogPlayback) {
NSLog(#"You CAN add to iCloud!");
} else {
NSLog(#"The ability to add Apple Music track is not there. sigh.");
}
}];
}];
You should check for the SKCloudServiceCapabilityMusicCatalogPlayback flag in capabilities. The code in your question checks whether the capabilities variable equals that flag, but you need to use bitwise operators. Here is how you'll do that.
SKCloudServiceController *controller = [SKCloudServiceController new];
[controller requestCapabilitiesWithCompletionHandler:^(SKCloudServiceCapability capabilities, NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Error getting SKCloudServiceController capabilities: %#", error);
} else if (capabilities & SKCloudServiceCapabilityMusicCatalogPlayback) {
// The user has an active subscription
} else {
// The user does *not* have an active subscription
}
}];
You can tell that SKCloudServiceCapabilityMusicCatalogPlayback is a flag and not just a regular constant value because the value uses bitwise operators (the "<<" shown in Apple's documentation).
SKCloudServiceCapabilityMusicCatalogPlayback = 1 << 0
https://developer.apple.com/reference/storekit/skcloudservicecapability/skcloudservicecapabilitymusiccatalogplayback?language=objc
I'm trying to configure an Open Graph post. I've followed the code examples on the FB developer site, and, using a test_user, a post is supposedly successfully generated. Here is my code:
- (void)createOGObjectForImage:(NSURL *)imageURL
{
NSMutableDictionary<FBGraphObject> *object =
[FBGraphObject openGraphObjectForPostWithType:#"ogminigame:mini_game"
title:#"Mini Game"
image:#"https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png"
url:imageURL
description:#""];
[FBRequestConnection startForPostWithGraphPath:#"me"
graphObject:object
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(!error) {
NSLog(#"Result: %#", [result description]);
[self createOGActionWithResult:result];
} else {
NSLog(#"Error posting the Open Graph object to the Object API: %#", error);
[self sharePhotoWithShareDialog:self openGraphAction:nil];
}
}];
}
However, nothing is appearing on the test user wall. When I step through the code, I can see that when I create the OG object, the result has the following contents:
"FACEBOOK_NON_JSON_RESULT" = true;
More specifically, it looks like this:
So when I create my Action, when I try to retrieve the objectID using:
NSString *objectId = [result objectForKey:#"id"];
it obviously returns nil. Am I missing a stage with the result object? I've tried searching for similar problems but there doesn't seem to be much in the way of an explanation.
Well, it seems the code supplied on the Facebook developer site where you supply your custom stories is incorrect. Namely, it should look like:
- (void)createOGObjectForImage:(NSURL *)imageURL
{
NSMutableDictionary<FBOpenGraphObject> *object = [FBGraphObject openGraphObjectForPostWithType:#"ogminigame:mini_game"
title:#"Mini Game"
image:#"https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png"
url:imageURL
description:#""];
[FBRequestConnection startForPostOpenGraphObject:object completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(!error) {
NSLog(#"Result: %#", [result description]);
[self createOGActionWithResult:result];
} else {
NSLog(#"Error posting the Open Graph object to the Object API: %#", error);
[self sharePhotoWithShareDialog:self openGraphAction:nil];
}
}];
}
So you cast the dictionary to an FBOpenGraphObject, rather than an FBGraphObject and call startForPostOpenGraphObject instead of startForPostWithGraphPath.
It seems to me Facebook need to be a bit more consistent with their documentation.
I still have nothing showing on the test_account page, but at least the above doesn't seem to be the cause of the issue...
When I want to get userID from Facebook, I need to wait the API "startWithCompletionHandler" to send me back the userID, then I continue my task. Just like the code listed below.
But I can not use dispatch_semaphore or dispatch_group to wait for the api to callback. Except for completionHandler, any other solution like "blockAndWait" in MagicalRecord that can help me solve question like this?
Also, the solution listed below isn't working. It seems blocked the main thread, so it'll keep logging "WAITING" and can not pop up the Facebook login view.
-(void)getAccountIDAndWait{
__block BOOL isFinish = NO;
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *aUser, NSError *error) {
if (error) {
NSLog(#"bug in getAccountIDAndWait");
return;
}
self.accountID = [aUser objectForKey:#"id"];
isFinish = YES;
}];
while(isFinish==NO){
sleep(0.1);
NSLog(#"WAITING");
}
}
Expanding on what Chuck said I've slightly modified your code to allow the getAccountIdAndWait function to finish (and thus the main thread to idle) and when the completionHandler is called it will call the doTheNextThing function.
-(void)getAccountIDAndWait{
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *aUser, NSError *error) {
if (error) {
NSLog(#"bug in getAccountIDAndWait");
return;
}
self.accountID = [aUser objectForKey:#"id"];
[self doTheNextThing];
}];
}
The approach you are using there is blocking. As you correctly observe, this is not really what you want. The design intent here is for you to put things that you want to happen after the request completes in the completion handler.
Is there a way to get all the GKAchievementDescription list with achievement status (locked, unlocked or percent) ?
I just logged that
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error)
{
NSLog(#"description %#",descriptions);
}];
but I can't figure out how to know each state of each achievement.
Here's an idea:
Do this:
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error)
{
for(GKAchievementDescription *myDescription in descriptions) {
for(GKAchievement *myAch in achievements) {
if ([myDescription.identifier isEqualToString:[myAch.identifier])
// the achievement is earned earned add it to array - do things - break;
}
}
}]; }];
The idea is when you get achievements with loadAchievementsWithCompletionHandler method, it only returns the submitted achievements. From there you can filter the required descriptions.
How to get game center achievements description into NSString?
Apple makes it very nice for you with this simple block method:
- (void) retrieveAchievmentMetadata {
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:
^(NSArray *descriptions, NSError *error) {
if (error != nil)
// process the errors
if (descriptions != nil)
// use the achievement descriptions.
}];
}
You can then extract the NSStrings from the descriptions array.
There is more documentation on this topic here: http://developer.apple.com/library/ios/#DOCUMENTATION/NetworkingInternet/Conceptual/GameKit_Guide/Achievements/Achievements.html
I hope this helps!