Reporting score to gamecenter for ios7 - ios7

According to https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/LeaderBoards/LeaderBoards.html
Reporting score to gamecenter in ios7 should be done using
[GKLeaderboard reportScores:scores withCompletionHandler:^(NSError *error) {
//Do something interesting here.
}];
However, I could not find any reference to this method in GKLeaderboard.
The method does not exist here:
https://developer.apple.com/library/ios/documentation/GameKit/Reference/GKLeaderboard_Ref/Reference/Reference.html
GKLeaderboard.h does not contain a reportScores method also.
The former way of reporting score using GKScore's reportScoreWithCompletionHandler method had been deprecated so I am reluctant to use that.
Does anyone know whats the correct way to report score to gamecenter in ios7?

I can confirm that the reportScores:withCompletionHandler: method does work; I'm using it in one of my apps. It's located in the header file GKScore.h. This is how I'm using it:
- (void) reportHighScore:(NSInteger) highScore {
if ([GKLocalPlayer localPlayer].isAuthenticated) {
GKScore* score = [[GKScore alloc] initWithLeaderboardIdentifier:MY_LEADERBOARD_ID];
score.value = highScore;
[GKScore reportScores:#[score] withCompletionHandler:^(NSError *error) {
if (error) {
// handle error
}
}];
}
}

Related

Apple Music detect is member

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

can't load Safari contentBlocker. because can't access app group's NSUserDefault

I am making iOS 9 Safari AdBlocker app.
I am using the module of AdBlockPlusSafari.
App works good on simulator.
But when try to run it on device(iPhone6), it fails to reload contentBlocker.
[SFContentBlockerManager
reloadContentBlockerWithIdentifier:self.contentBlockerIdentifier
completionHandler:^(NSError *error) {
if (error) {
NSLog(#"Error in reloadContentBlocker: %#", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
wSelf.reloading = NO;
[wSelf checkActivatedFlag];
if (completion) {
completion(error);
}
});
}];
it gives error
Error Domain=ContentBlockerErrorDomain Code=3 "(null)"
It caused by accessing the values in NSUserDefault (App Group).
- (instancetype)init
{
if (self = [super init])
{
_bundleName = [[[[[NSBundle mainBundle] bundleIdentifier] componentsSeparatedByString:#"."] subarrayWithRange:NSMakeRange(0, 2)] componentsJoinedByString:#"."];
NSString *group = [NSString stringWithFormat:#"group.%#.%#", _bundleName, #"AdBlockerPro"];
NSLog(#"Group name: %#", group);
_adblockProDetails = [[NSUserDefaults alloc] initWithSuiteName:group];
[_adblockProDetails registerDefaults:
#{ AdblockProActivated: #NO,
AdblockProEnabled: #YES
}];
_enabled = [_adblockProDetails boolForKey:AdblockProEnabled];
_activated = [_adblockProDetails boolForKey:AdblockProActivated];
}
return self;
}
The App Group name in host app and safari extension is same.
But in Safari extension, when app accesses the setting in NSUserDefault, it gives me the error.
In Project setting/Capabilities, I did all for App Group. In app id, it involves app group name exactly.
This happens on only device. On simulator, it works good. I can't find the reason of this error.
Please help me if you are experienced this.
Looking forward to your help.
I found the reason myself.
I have put something (NSMutableDictionary) in app group container and did something to write file to extension bundle.
It is prohibited by Apple.
So I deleted all from AdBlockManager (interacts with app group) except flag variables (Boolean type).
And I proceeded the file management using NSFileManager.
http://www.atomicbird.com/blog/sharing-with-app-extensions
Finally, app extension is working for me on device.
Good luck!

Use the variable after block successful completion

I'm working on a simple instagram project now.
for several occasions I've encountered the same problem.
To work with instagram I use InstagramKit Engine. It has some preset (void)s to make life easier. However I'm always stuck at the same problem.
Let's say we've got this:
- (void)getSelfUserDetails
{
[[InstagramEngine sharedEngine] getSelfUserDetailsWithSuccess:^(InstagramUser *userDetail) {
NSLog(#"%#",userDetail);
} failure:^(NSError *error) {
}];
}
Here userDetail is used inside of the "Success". And it works nice. What I need is to somehow save it after the block is done.
I've tried several things from creating a property to store the userDetails up to making my own method to return the userDetails. The same trouble with saving ints, NSStrings etc..
I think I'm missing some easy way out.
Show it to me please.
You need to capture an object in the block that you can send the response object.
This can be self.
-(void)processUserDetails:(InstagramUser *) userDetail
{
//....
}
- (void)getSelfUserDetails
{
[[InstagramEngine sharedEngine] getSelfUserDetailsWithSuccess:^(InstagramUser *userDetail) {
[self processUserDetails: userDetail];
} failure:^(NSError *error) {
}];
}
You could create a property to hold the Instagram user that you find and assign it to it in the success block:
#property (nonatomic) InstagramUser *myUser;
- (void)getSelfUserDetails
{
[[InstagramEngine sharedEngine] getSelfUserDetailsWithSuccess:^(InstagramUser *userDetail) {
NSLog(#"%#",userDetail);
self.myUser = userDetail;
} failure:^(NSError *error) {
}];
}
This is a good use for an NSNotification (since the call above happens asynchronously).
You could call it like:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self
userInfo:#{ #"userDetail" : userDetail }
];
And then get that userInfo data back with whatever method is listening for that event.

Game Center report in iOS 7 (Deprecated)

My IDE show warning "Obsolete: Deprecated in iOS 7.0" this methods:
(GKScore) ReportScore()
(GKAchievement) ReportAchievement()
This methods it works on iOS 7, but use not problem? Exist other methods on iOS 7?
Thanks!
I used this method to report score in game center and it works.
-(void)reportScore
{
if(isIOS7)
{
// Create a GKScore object to assign the score and report it as a NSArray object.
GKScore *score = [[GKScore alloc] initWithLeaderboardIdentifier:_leaderboardIdentifier];
score.value = _score;
[GKScore reportScores:#[score] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"score reporting error : %#", [error localizedDescription]);
}
else
{
NSLog(#"score reported.");
}
}];
}
else
{
GKScore *scoreReporter = [[GKScore alloc] initWithCategory:_leaderboardIdentifier];
scoreReporter.value = _score;
scoreReporter.context = 0;
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
// Do something interesting here.
if (error != nil) {
NSLog(#"score reporting error : %#", [error localizedDescription]);
}
else
{
NSLog(#"score reported.");
}
}];
}
}
Objective-C methods start with a lower-case method. They are not called with rounded brackets. So, I:
opened the documentation for GKScore;
looked for anything deprecated and found -reportScoreWithCompletionHandler:;
saw that +reportScores: withCompletionHandler: isn't deprecated.
And saw pretty much the same thing with the singular instance method being deprecated in favour of the collection class method in GKAchievement.
So: just use the collection methods. Deprecated methods hang around being unsupported for a while and then disappear. You can find out what's currently supported, very very quickly, by reading the documentation.

What's the correct use of NSErrorRecoveryAttempting, NSError, and UIAlertView in iOS?

I'm having trouble finding examples of the correct way to use NSError, UIAlertView, and NSErrorRecoveryAttempting together on iOS. Most of the documentation and examples I can find cover the equivalent functionality on OS X, where the relevant behaviors are integrated by Cocoa. But in iOS it seems to be necessary do do this "by hand", and I can't find good examples of how it's done.
I'd very much appreciate a few examples of best practice in using information in NSError to support recovery attempts from NSErrors reported to the user.
According to Apple's documentation:
Important: The NSError class is available on both Mac OS X and iOS. However, the error-responder and error-recovery APIs and mechanisms are available only in the Application Kit (Mac OS X).
So, I'm not sure if you can use NSErrorRecoveryAttempting even though it does appear to be defined in the documentation (it looks like this is an area of the UIKit docs that have not yet been updated after being copied from AppKit's documentation).
Here is how I handle errors in my code:
NSError *error = nil;
id result = [SomeClass doSomething:&error];
if (!result) {
NSLog(#"Do something failed: %#", error);
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Something failed!" message:#"There was an error doing something." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alert show];
return;
}
I found a great example of this.
See the following blog post and GitHub code (including sample project) by James Beith
http://www.realmacsoftware.com/blog/cocoa-error-handling-and-recovery
https://github.com/realmacsoftware/RMErrorRecoveryAttempter
I was able to successfully use this on the iPhone simulator.
I'm trying to mirror AppKit's error handling mechanism in UIKit, mainly because I want to take advantage of the responder chain to forward errors upwards. I haven't tested this fully, but at the moment it's looking like below.
It reflects AppKit pretty closely, but the will/did hooks can be overridden to perform custom error presentation and recovery respectively. The default behaviour is to show a UIAlertView for presentation and use a psuedo-NSErrorRecoveryAttempting object for recovery.
#implementation UIResponder (ErrorHandling)
- (void)presentError:(NSError *)error
completion:(void (^)(BOOL recovered))completion
{
if (nil == (error = [self willPresentError:error])) {
return;
}
if (self.nextResponder) {
[self.nextResponder presentError:error completion:completion];
return;
}
// Code to create and show UIAlertView
// e.g. https://github.com/jayway/CWUIKit/blob/master/Classes/UIAlertView%2BCWErrorHandler.m
// The UIAlertViewDelegate calls didPresentError...
}
/*
Override to customise the error object as in AppKit.
You can also perform your own error presentation, and return nil to terminate the default handling.
Custom error presentation UI should still call didPresentError... when dismissed
*/
- (NSError *)willPresentError:(NSError *)error
{
return error;
}
/*
Override to perform custom error recovery.
*/
- (void)didPresentError:(NSError *)error optionIndex:(NSInteger)optionIndex completion:(void (^)(BOOL recovered))completion
{
id recoveryAttempter = [error recoveryAttempter];
if ([recoveryAttempter respondsToSelector:#selector(attemptRecoveryFromError:optionIndex:completion:)]) {
[recoveryAttempter attemptRecoveryFromError:error optionIndex:optionIndex completion:completion];
}
}
#end