reportAchievementWithCompletionHandler deprecated in iOS7 but replacement not specified - ios

Has anyone found the replacement for
[GKAchievement reportAchievementWithCompletionHandler]?
Typically when things are deprecated the docs indicate a replacement. Not so with this one so far and I wanted to cross this off the list of possible causes of another issue we are seeing.

Was looking for the same info and saw your post, here is what I went with after not finding anything either:
NSArray *achievements = [NSArray arrayWithObjects:achievement, nil];
[GKAchievement reportAchievements:achievements withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"Error in reporting achievements: %#", error);
}
}];

Here is apple's full code (same/similar to Silly Goose's Answer)
- (void) completeMultipleAchievements
{
GKAchievement *achievement1 = [[GKAchievement alloc] initWithIdentifier: #"DefeatedFinalBoss"];
GKAchievement *achievement2 = [[GKAchievement alloc] initWithIdentifier: #"FinishedTheGame"];
GKAchievement *achievement3 = [[GKAchievement alloc] initWithIdentifier: #"PlayerIsAwesome"];
achievement1.percentComplete = 100.0;
achievement2.percentComplete = 100.0;
achievement3.percentComplete = 100.0;
NSArray *achievementsToComplete = [NSArray arrayWithObjects:achievement1,achievement2,achievement3, nil];
[GKAchievement reportAchievements: achievementsToComplete withCompletionHandler:^(NSError *error)
{
if (error != nil)
{
NSLog(#"Error in reporting achievements: %#", error);
}
}];
}

This works in iOS7 with no issues.
- (void)checkAchievements
{
if(myScore >= 25000){
GKAchievement *achievement= [[GKAchievement alloc] initWithIdentifier:#"Achiev1"];
achievement.percentComplete = 100.0;
achievement.showsCompletionBanner = YES;
[self Achievements:achievement];
}
}
-(void)Achievements:(GKAchievement*)achievement {
NSArray *achievements = [NSArray arrayWithObjects:achievement, nil];
[GKAchievement reportAchievements:achievements withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"Error in reporting achievements: %#", error);
}
}];
}

Related

startVPNTunnelWithOptions doesnt return with error

I'm trying to set up customized vpn tunnel
- (void) openTunnel{
[vpnManager loadFromPreferencesWithCompletionHandler:^(NSError *error){
if(error != nil){
NSLog(#"%#", error);
}else{
NSError *startError = nil;
[self->vpnManager.connection startVPNTunnelWithOptions:nil andReturnError:&startError];
if(startError != nil){
NSLog(#"viewcontroller: startError: %#", startError);
}else{
NSLog(#"Complete");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:NEVPNStatusDidChangeNotification
object:nil];
}
}
}];}
startVPNTunnelWithOptions starts a customized tunnel as following
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completion{
NSLog(#"===> ");
NSError *error = nil;
vpnAdapter = [[OpenAdapter alloc] init];
vpnAdapter.delegate = self;
// get config
config = [[NSDictionary alloc] init];
NETunnelProviderProtocol *protocol = (NETunnelProviderProtocol *)self.protocolConfiguration;
config = protocol.providerConfiguration;
host = config[#"server"];
// Load config data
username = config[#"username"];
password = config[#"password"];
option = config[#"option"];
NSError *newError = [NSError errorWithDomain:VPNTunnelProviderErrorDomain
code:TunnelProviderErrorCodeInvalidConfiguration
userInfo:#{NSLocalizedDescriptionKey: #"Settings validation failed!"}];
if(option != nil){
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(int success) {
if(success == 0)
{NSLog(#"packettunnel: newerror: %d", 0);
completion(error);}
else {
NSLog(#"packettunnel: newerror: %#", newError);
completion(newError);
}
}];
}else{
[vpnAdapter connect:host user:username pass:password add:NO completionHandler:^(int success) {
if(success == 0){
{NSLog(#"packettunnel: newerror: %d", 0);
completion(error);}
else
{
NSLog(#"packettunnel: newerror: %#", newError);
completion(newError);
}
}];
}
}
when testing with fake credentials(works fine with correct one), it supposed to print startError, but it doesn't. I can confirm that startTunnelWithOptions it actually returns newError from NSLog, but somehow, startVPNTunnelWithOptions doesn't return any error.
anyone could help?
thanks

iOS NETunnelProviderManager saving multiple configurations

I'm trying to save my VPN configuration to the preferences, which already works (I'm able to connect to my VPN). But for some reason each time i run the code again instead of using the last configuration it creates a new one. So, i end up with a bunch of configurations.
Here is my current code, if anyone could let me know what's going wrong with it that would be awesome. Thanks!
// Initialize Manager
NETunnelProviderManager *manager = [[NETunnelProviderManager alloc] init];
[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
if (error) {
NSLog(#"Load Error: %#", error.description);
} else {
// Create the protocol object
NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init]; // Create the protocol object
// Configure the protocol object
protocol.providerBundleIdentifier = #"com.nfisc.testvpn.ptp"; // Bundle ID of tunnel provider
protocol.providerConfiguration = #{}; // Currently blank, but will be used later
protocol.serverAddress = #"0.0.0.0"; // Ommited for security reasons
protocol.username = #"username"; // The username for the configuration
protocol.identityDataPassword = #"password"; // The password for the configuration
protocol.disconnectOnSleep = NO;
// Configure the manager with the protocol
manager.protocolConfiguration = protocol;
manager.enabled = true;
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
if (error) {
NSLog(#"Save Error: %#", error.description);
} else {
if ([[manager connection] status] != NEVPNStatusConnected) {
NSLog(#"Starting VPN");
[self start:manager];
} else {
NSLog(#"VPN Already Connected");
[_statusLabel setText:#"Connected"];
[_statusLabel setTextColor:[UIColor greenColor]];
}
}
}];
}
}];
Use + (void)loadAllFromPreferencesWithCompletionHandler:(void (^)(NSArray<NEAppProxyProviderManager *> *managers, NSError *error))completionHandler API instead.
create new protocol only when managers.count == 0 in the block.
[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray<NETunnelProviderManager *> * _Nullable managers, NSError * _Nullable error) {
if (error) {
NSLog(#"Load Error: %#", error.description);
}
NETunnelProviderManager *manager;
if (managers.count > 0) {
manager = managers[0];
}else {
manager = [[NETunnelProviderManager alloc] init];
manager.protocolConfiguration = [[NETunnelProviderProtocol alloc] init];
}
//... your code here...
}];
The solution was to call [NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler: first and then do the rest.
Fixed Code:
__block NETunnelProviderManager *manager = [[NETunnelProviderManager alloc] init];
NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];
protocol.providerBundleIdentifier = #"com.nfisc.testvpn.ptp"; // bundle ID of tunnel provider
protocol.providerConfiguration = #{#"key": #"value"};
protocol.serverAddress = #"0.0.0.0"; // VPN server address
protocol.username = #"username";
protocol.identityDataPassword = #"password";
manager.protocolConfiguration = protocol;
manager.enabled = true;
[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray<NETunnelProviderManager *> * _Nullable managers, NSError * _Nullable error) {
if ([managers count] > 0) {
manager = [managers objectAtIndex:0];
[self start:manager];
} else {
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
if (error) {
NSLog(#"Error 1: %#", error.description);
} else {
[manager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(#"Error 2: %#", error.description);
} else {
[self start:manager];
}
}];
}
}];
}
}

STTwitterAPI to pull number of tweets,followers and following?

I am trying to create a profile inside my application to show only his twitter profile. So far I do have the time line working but I don't have the number counter for the tweets,followers and following. I'm pretty sure I can use something what my code looks like but just don't know how, any help? Thanks
Code:
STTwitterAPI *twitter = [STTwitterAPI twitterAPIAppOnlyWithConsumerKey:#"ConsumerKey"
consumerSecret:#"consumerSecret"];
[twitter verifyCredentialsWithSuccessBlock:^(NSString *bearerToken) {
[twitter getUserTimelineWithScreenName:#"MikesiOSHelp"
successBlock:^(NSArray *statuses) {
self.twitterFeed = [NSMutableArray arrayWithArray:statuses];
[self->tableView reloadData];
} errorBlock:^(NSError *error) {
NSLog(#"%#", error.debugDescription);
}];
} errorBlock:^(NSError *error) {
NSLog(#"%#", error.debugDescription);
}];
You should check out their demo application.
Your request for finding the followers of a user is explicitly covered in the CLI demo:
typedef void (^AllFollowersBlock_t)(NSArray *allFollowers);
void getFollowers(STTwitterAPI *twitter,
NSString *screenName,
NSMutableArray *followers,
NSString *cursor,
AllFollowersBlock_t allFollowersBlock) {
if(followers == nil) followers = [NSMutableArray array];
NSMutableDictionary *md = [NSMutableDictionary dictionary];
md[#"screen_name"] = screenName;
if(cursor) md[#"cursor"] = cursor;
md[#"skip_status"] = #"1";
md[#"include_user_entities"] = #"0";
[twitter getResource:#"followers/list.json"
baseURLString:kBaseURLStringAPI_1_1
parameters:md
downloadProgressBlock:^(id json) {
//
} successBlock:^(NSDictionary *rateLimits, id response) {
NSArray *users = nil;
NSString *previousCursor = nil;
NSString *nextCursor = nil;
if([response isKindOfClass:[NSDictionary class]]) {
users = [response valueForKey:#"users"];
previousCursor = [response valueForKey:#"previous_cursor_str"];
nextCursor = [response valueForKey:#"next_cursor_str"];
}
NSLog(#"-- users: %#", #([users count]));
NSLog(#"-- previousCursor: %#", previousCursor);
NSLog(#"-- nextCursor: %#", nextCursor);
[followers addObjectsFromArray:users];
if([nextCursor integerValue] == 0) {
allFollowersBlock(followers);
return;
}
/**/
NSString *remainingString = [rateLimits objectForKey:#"x-rate-limit-remaining"];
NSString *resetString = [rateLimits objectForKey:#"x-rate-limit-reset"];
NSInteger remainingInteger = [remainingString integerValue];
NSInteger resetInteger = [resetString integerValue];
NSTimeInterval timeInterval = 0;
if(remainingInteger == 0) {
NSDate *resetDate = [[NSDate alloc] initWithTimeIntervalSince1970:resetInteger];
timeInterval = [resetDate timeIntervalSinceDate:[NSDate date]] + 5;
}
NSLog(#"-- wait for %# seconds", #(timeInterval));
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
getFollowers(twitter, screenName, followers, nextCursor, allFollowersBlock);
});
} errorBlock:^(NSError *error) {
NSLog(#"-- error: %#", error);
}];
}

load Game Center friends and their scores into UITableView

So I was wondering after reading the apple docs(https://developer.apple.com/library/ios/documentation/GameKit/Reference/GKLeaderboard_Ref/Reference/Reference.html#//apple_ref/occ/instp/GKLeaderboard/category) how would one create a UITableView and fill it with the localPlayers Game Center friends and there scores in a specific leaderboard. I know how to get the friends list and friends scores individually by using the loadScoresWithCompletionHandler: method.
Edit: So far I got this to get individual friends photo, score and displayname saved into one NSArray. But i can't figure out how to disply them in a UITableView.
- (void) loadPlayerData: (NSArray *) identifiers
{
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil) {
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = #"MJ_IL";
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil) {
// handle the error. if (scores != nil)
}
if (scores != nil){
for (GKScore* score in scores) {
NSArray *playerIdArray = [NSArray arrayWithObject:score.playerID];
[GKPlayer loadPlayersForIdentifiers:playerIdArray withCompletionHandler:^(NSArray *players, NSError *error) {
GKPlayer *player = [players objectAtIndex:0];
[player loadPhotoForSize:GKPhotoSizeSmall withCompletionHandler:^(UIImage *photo, NSError *error) {
if (score.playerID == player.playerID) {
if (photo != nil) {
playerInfo = [NSArray arrayWithObjects:score, player.displayName, photo, nil];
} else if (photo == nil) {
playerInfo = [NSArray arrayWithObjects:score, player.displayName, nil];
}
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
}
}
}];
}];
}
}
}];
}
}
- (void)compareLocalPlayerScoreWithFriends {
GKScore *friendScore = [playerInfo objectAtIndex:0];
NSString *friendDisplayName = [playerInfo objectAtIndex:1];
if ([playerInfo objectAtIndex:2] != nil) {
UIImage *friendPhoto = [playerInfo objectAtIndex:2];
if (friendScore.value > interactiveHighscore) {
[friendNameLabel setText:friendDisplayName];
[friendScoreLabel setText:(NSString *)friendScore];
friendImageView.image = friendPhoto;
}
}
}
Thanks guys,
Georges
Take a look at this tutorial by Ray Wenderlich, it explains how to display simple pictures and text in a UITableView - there are three parts and should get you working with, at least, a basic but working view.
At its very core level this is the code that does "the work" for displaying in a UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"MyBasicCell"];
ScaryBugDoc *bug = [self.bugs objectAtIndex:indexPath.row];
cell.textLabel.text = bug.data.title;
cell.imageView.image = bug.thumbImage;
return cell;
}
Update
Here is my code for generating leaderbord data with alias and photos, hope you can modify it appropriately but shouldnt be too different
-(void)getScoresAndAliasForLeaderboard:(GKLeaderboard *)leaderboardRequest{
if (leaderboardRequest == nil)
{
leaderboardRequest = [[GKLeaderboard alloc] init];
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = #"HighScore";
leaderboardRequest.range = NSMakeRange(1,100);
}
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
// Handle the error.
}
if (scores != nil)
{
NSMutableArray *retrievePlayerIDs = [[NSMutableArray alloc] init];
for (GKScore *s in scores)
{
[retrievePlayerIDs addObject:s.playerID];
GCLeaderboardScore *playerScore = [[GCLeaderboardScore alloc] init];
playerScore->playerID = s.playerID;
playerScore->score = (int)s.value;
playerScore->rank = s.rank;
playerScores[s.playerID] = playerScore; //playerScores is a NSMutableDictionary
if ([s.playerID isEqualToString: leaderboardRequest.localPlayerScore.playerID]){
me = playerScore;
}
}
if (me == nil){
me = [[GCLeaderboardScore alloc] init];
me->playerID = leaderboardRequest.localPlayerScore.playerID;
me->score = leaderboardRequest.localPlayerScore.value;
me->alias = #"Me";
playerScores[me->playerID] = me;
}
[GKPlayer loadPlayersForIdentifiers:retrievePlayerIDs withCompletionHandler:^(NSArray *playerArray, NSError *error)
{
for (GKPlayer* p in playerArray)
{
GCLeaderboardScore *playerScore = playerScores[p.playerID];
playerScore->alias = p.alias;
[p loadPhotoForSize:GKPhotoSizeSmall withCompletionHandler:^(UIImage *photo, NSError *error) {
if (photo != nil) {
playerScore->photo = photo;
}
else{
playerScore->photo = [UIImage imageNamed:#"wordpress_avatar.jpg"];
}
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
}
}];
}
}];
}
}];
}

not sure why my loadmatcheswithmatchdata isn't working

I'm creating a public method to return all of my matches from my gamecenterhelper.m
I have this:
+(NSArray *)retrieveMatchesWithMatchData {
__block NSArray *myMatches = nil;
[GKTurnBasedMatch loadMatchesWithCompletionHandler:^(NSArray *matches, NSError *error) {
if (error) {
NSLog(#"There was an error loading matches");
}
else {
myMatches = matches;
}
}];
return myMatches;
}
but this returns null when I call it, even though I have active matches. the call method looks like this:
NSLog(#"My matches: %#",[GameCenterHelper retrieveMatchesWithMatchData]);
Thanks for your time!
Thats the nature of blocks. Your block is executed asynchronously. You cannot load Game Center matches synchronously. Let's make this an instance method:
-(void)retrieveMatchesWithMatchData {
[GKTurnBasedMatch loadMatchesWithCompletionHandler:^(NSArray *matches, NSError *error) {
if (error) {
NSLog(#"There was an error loading matches");
}
else {
[self matchesLoaded:matches];
}
}];
}
Then you process the matches in this method:
-(void)matchesLoaded:(NSArray *)matches {
//do something with your matches
}
EDIT:
There is an easy way to do what you want. You can use Apples standard view controller to show current matches:
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = minPlayers;
request.maxPlayers = maxPlayers;
GKTurnBasedMatchmakerViewController *mmvc =
[[GKTurnBasedMatchmakerViewController alloc]
initWithMatchRequest:request];
mmvc.turnBasedMatchmakerDelegate = self;
mmvc.showExistingMatches = YES;
[self presentViewController:mmvc animated:NO completion:nil];

Resources