I need to retrieve a player's top submitted score from Game Center. I think I found the answer in objective C, but I don't know how to write it in swift since I am fairly new to this. Can someone help me translate the following code into swift? Thank you in advance.
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil) {
[leaderboardRequest loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error){
if (error != nil) {
//Handle error
}
else{
[delegate onLocalPlayerScoreReceived:leaderboardRequest.localPlayerScore];
}
}];
}
Here's a straight translation to Swift:
let leaderboardRequest = GKLeaderboard() as GKLeaderboard!
if leaderboardRequest != nil
{
leaderboardRequest.loadScoresWithCompletionHandler({ (scores:[AnyObject]!, error:NSError!) -> Void in
if error != nil
{
//handle error
}
else
{
delegate.onLocalPlayerScoreReceived(leaderboardRequest.localPlayerScore)
}
})
}
Related
I am trying to implement new iOS9 feature app thinning, I understood how tag an image and enable on demand resource in Xcode 7 but I don't understand how to implement NSBundleResourceRequest in my app, can someone help me, that would greatly appreciated
Most of information is available in Apple documentation.
Basically you need make this:
NSSet *tagsSet = [NSSet setWithObjects:#"resourceTag1", #"resourceTag2", nil];
NSBundleResourceRequest *request = [[NSBundleResourceRequest alloc] initWithTags:tagsSet];
[request conditionallyBeginAccessingResourcesWithCompletionHandler:^(BOOL resourcesAvailable) {
if (resourcesAvailable) {
// Start using resources.
} else {
[request beginAccessingResourcesWithCompletionHandler:^(NSError * _Nullable error) {
if (error == nil) {
// Start using resources.
}
}];
}
}];
First, check if the resources are available. Else download them.
Here is the swift code I use
let tags = NSSet(array: ["tag1","tag2"])
let resourceRequest = NSBundleResourceRequest(tags: tags as! Set<String>)
resourceRequest.conditionallyBeginAccessingResourcesWithCompletionHandler {(resourcesAvailable: Bool) -> Void in
if resourcesAvailable {
// Do something with the resources
} else {
resourceRequest.beginAccessingResourcesWithCompletionHandler {(err: NSError?) -> Void in
if let error = err {
print("Error: \(error)")
} else {
// Do something with the resources
}
}
}
}
I also found this guide very helpful.
I was able to get all the playlist of users using spotify ios sdk, this is my code.
[SPTPlaylistList playlistsForUserWithSession:session callback:^(NSError *error, id object) {
SPTListPage *pl= object;
NSLog(#"%#",pl.items);
}];
But I am not sure now How to get all the tracks of these playlists. any help?
Because this Spotify ios SDK v10beta is new and with many incomplete tasks, to access and be able to play all tracks in your playlists you have to run through many blocks.
First I would recommend to get the first SPTListPage object of all the playlists:
-(void)getFirstPlaylistPage
{
[SPTPlaylistList playlistsForUserWithSession:[SPTAuth defaultInstance].session callback:^(NSError *error, SPTListPage *playlistsPage) {
if (error != nil) {
NSLog(#"*** Getting playlists got error: %#", error);
return;
}
if (playlistsPage==nil) {
NSLog(#"*** No playlists were found for logged in user. ***");
return;
}
[self getFullPlaylistPage:playlistsPage];
}];
}
Then, merge all SPTListPage objects into one:
-(void)getFullPlaylistPage:(SPTListPage*)listPage {
if (listPage.hasNextPage) {
[listPage requestNextPageWithSession:[SPTAuth defaultInstance].session callback:^(NSError *error, SPTListPage* playlistPage) {
if (error != nil) {
NSLog(#"*** Getting playlist page got error: %#", error);
return;
}
listPage = [listPage pageByAppendingPage:playlistPage];
[self getFullPlaylistPage:listPage];
}];
} else {
NSMutableArray* playlist = [[NSMutableArray alloc]init];
[self convertPlaylists:listPage arrayOfPlaylistSnapshots:playlist positionInListPage:0];
}
}
Now, SPTListPage contains SPTPartialPlaylist objects, which do not contain all the info of the playlists, so we need to convert it to SPTPlaylistSnapshot object:
-(void)convertPlaylists:(SPTListPage*)playlistPage arrayOfPlaylistSnapshots:(NSMutableArray*)playlist positionInListPage:(NSInteger)position
{
if (playlistPage.items.count > position) {
SPTPartialPlaylist* userPlaylist = playlistPage.items[position];
[SPTPlaylistSnapshot playlistWithURI:userPlaylist.uri session:[SPTAuth defaultInstance].session callback:^(NSError *error, SPTPlaylistSnapshot* playablePlaylist) {
if (error != nil) {
NSLog(#"*** Getting playlists got error: %#", error);
return;
}
if(!playablePlaylist){
NSLog(#"PlaylistSnapshot from call back is nil");
return;
}
[playlist addObject:playablePlaylist];
[self convertPlaylists:playlistPage arrayOfPlaylistSnapshots:playlist positionInListPage:position+1];
}];
} else {
// send your array of playlists somewhere example:
[self addSongs];
}
}
Now you can access all the playlists and all the songs in them with a simple loop-through.
I hope spotify will improve here as it is not how it supposed to be. Come on,Spotify!
Using Swift3:
After authentication, define a playlist request , like this:
let playListRequest = try! SPTPlaylistList.createRequestForGettingPlaylists(forUser: userName, withAccessToken: token)
I use alamofire to post this request:
Alamofire.request(playListRequest)
.response { response in
let list = try! SPTPlaylistList(from: response.data, with: response.response)
for playList in list.items {
if let playlist = playList as? SPTPartialPlaylist {
print( playlist.name ) // playlist name
print( playlist.uri) // playlist uri
let stringFromUrl = playlist.uri.absoluteString
let uri = URL(string: stringFromUrl)
// use SPTPlaylistSnapshot to get all the playlists
SPTPlaylistSnapshot.playlist(withURI: uri, accessToken: token!) { (error, snap) in
if let s = snap as? SPTPlaylistSnapshot {
// get the tracks for each playlist
print(s.name)
for track in s.firstTrackPage.items {
if let thistrack = track as? SPTPlaylistTrack {
print(thistrack.name)
}
}
}
}
}
}
}
I am making a game in Swift. I want to be able to post the users' score using GameCenter, so that scores from all my users' can be seen. However, I have spent the past day trying to figure out how to do this, but I haven't found any helpful instructions.
I am pretty new to iOS programming, and Swift, and of the very little amount of information on this subject, it's all written in Objective-C.
Can anyone help me integrate GameCenter into my app, so that I can post users scores to the leaderboards for people to see?
EDIT: I have already created a GameCenter leaderboard on iTunesConnect.
EDIT 2: I have tried following this tutorial: http://www.appcoda.com/ios-game-kit-framework/ and converting it to Swift. I have converted this:
-(void)authenticateLocalPlayer {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES;
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else {
_gameCenterEnabled = NO;
}
}
};
}
into this:
func authenticateLocalPlayer() {
var localPlayer : GKLocalPlayer!
localPlayer.authenticateHandler = {(viewController : MenuViewController!, error : NSError!) -> Void in
if viewController != nil {
self.presentViewController(viewController, animated: true, completion: nil)
} else {
if localPlayer.authenticated {
self.gameCenterEnabled = true
localPlayer.loadDefaultLeaderboardIdentifierWithCompletionHandler({ (leaderboardIdentifier : String!, error : NSError!) -> Void in
if error != nil {
println(error.localizedDescription)
} else {
self.leaderboardIdentifier = leaderboardIdentifier
}
})
} else {
self.gameCenterEnabled = false
}
}
}
}
but it crashes on this line:
localPlayer.authenticateHandler = {(viewController : UIViewController!, error : NSError!) -> Void in
The Error message is:
fatal error: unexpectedly found nil while unwrapping an Optional value
I can't believe how hard this is!
Your specific issue has nothing to do with Game Center and is happening because you have the line var localPlayer : GKLocalPlayer!.
You're declaring an implicitly unwrapped optional and then using it right away. It's value is nil in the subsequent line when you try to set localPlayer.authenticateHandler.
Instead you should instantiate GKLocalPlayer like so:
var localPlayer = GKLocalPlayer()
Note that there are currently issues with Game Center and Swift. Your code is going to work but localPlayer.authenticated never gets set to true. This issue is tracked here:
http://www.openradar.me/17825348
Credit to: http://www.stuarticus.net/blog/2014/7/game-center-authentication-and-swift
for filing the radar ticket.
You can use that, I create a simple class for iOS game center in github
Easy Class Game Center Swift
https://github.com/DaRkD0G/Easy-Game-Center-Swift
I have been playing with icloud in the ios 8 beta, and the CloudKitAtlasAnIntroductiontoCloudKit sample project has been very helpful.
https://developer.apple.com/library/prerelease/ios/samplecode/CloudAtlas/Introduction/Intro.html
But I wanted to use the CKDiscoverAllContactsOperation class and I cannot find any sample code for it anywhere at all and the online documentation is not very helpful.
https://developer.apple.com/library/prerelease/ios/documentation/CloudKit/Reference/CKDiscoverAllContactsOperation_class/index.html
If anyone has managed to successfully use CKDiscoverAllContactsOperation could you please help point me in the right direction or show a working example of how it should be called?
I have tried this to see if I could even get an response from iCloud but nothing:
- (void)queryForRecordsOtherUsersInAddressBookcompletionHandler:(void (^)(NSArray *records))completionHandler {
CKDiscoverAllContactsOperation *discoverAllContactsOperation= [[CKDiscoverAllContactsOperation alloc] init];
[discoverAllContactsOperation setContainer:_container];
NSMutableArray *results = [[NSMutableArray alloc] init];
discoverAllContactsOperation.discoverAllContactsCompletionBlock = ^(NSArray *userInfos, NSError *operationError) {
[results addObjectsFromArray:userInfos];
};
discoverAllContactsOperation.discoverAllContactsCompletionBlock=^(NSArray *userInfos, NSError *operationError){
if (operationError) {
// In your app, handle this error with such perfection that your users will never realize an error occurred.
NSLog(#"An error occured in %#: %#", NSStringFromSelector(_cmd), operationError);
abort();
} else {
dispatch_async(dispatch_get_main_queue(), ^(void){
completionHandler(results);
});
}
};
}
and calling with this...
[self.cloudManager queryForRecordsOtherUsersInAddressBookcompletionHandler:^(NSArray *records ) {
if (records.count==0){
NSLog(#"Login name not found");
return;
}
//self.results= records;
//_loggedInRecord = self.results[0];
//NSLog(#"%#,%#",_loggedInRecord[#"lastName"],_loggedInRecord[#"firstName"]);
// [self performSegueWithIdentifier:#"loggedInSegue" sender:self ];
}];
I know the code shouldn't really do anything. Again I was just looking for a response from iCloud.
Here is what I am using. self.container is a CKContainer set with [CKContainer defaultContainer] in the init.
-(void)queryForAllUsers: (void (^)(NSArray *records))completionHandler {
CKDiscoverAllContactsOperation *op = [[CKDiscoverAllContactsOperation alloc] init];
[op setUsesBackgroundSession:YES];
op.queuePriority = NSOperationQueuePriorityNormal;
[op setDiscoverAllContactsCompletionBlock:^(NSArray *userInfos, NSError *error) {
if (error) {
NSLog(#"An error occured in %#: %#", NSStringFromSelector(_cmd), error);
//abort();
} else {
// NSLog(#"Number of records in userInfos is: %ld", (unsigned long)[userInfos count]);
dispatch_async(dispatch_get_main_queue(), ^(void){
completionHandler(userInfos);
});
}
}];
[self.container addOperation:op];
}
Before you can use the CKDiscoverAllContactsOperation operation, you first need to request for permission.
Pls use the method requestApplicationPermission:completion:
func discoverAllContacts() {
let container = CKContainer.defaultContainer()
//Request for user permission
container.requestApplicationPermission([.UserDiscoverability]) { [weak self] status, error in
switch status {
case .Granted where error == nil:
let operation = self?.discoverAllContactsOperation { usersInfo in
//do something here
}
if let operationExists = operation {
//Assuming there is a NSOperationQueue property called operationQueue
self?.operationQueue.addOperation(operationExists)
}
default:
break
}
}
}
func discoverAllContactsOperation(completionHandler: ([CKDiscoveredUserInfo]?) -> ()) -> NSOperation {
let operation = CKDiscoverAllContactsOperation()
operation.discoverAllContactsCompletionBlock = { usersInfo, error in
if error == nil {
print("Discoverd all contacts = \(usersInfo)")
completionHandler(usersInfo)
}
else {
print("Discoverd all contacts error = \(error)")
completionHandler(nil)
}
}
return operation
}
I'm using the following method to retrieve the top 100 scores from one of my gamecenter leaderboards. Everything is working, correctly, except that as I retrieve a score, I'd like to add them up, so that once it is done, I have 1 total score.
How could I fix it?
- (void) retrieveTop100Scores {
GKLeaderboard *leaderboard1 = [[GKLeaderboard alloc] init];
leaderboard1.identifier = [Team currentTeam];
leaderboard1.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboard1.playerScope = GKLeaderboardPlayerScopeGlobal;
leaderboard1.range = NSMakeRange(1, 100);
[leaderboard1 loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil) {
for (GKScore *score in scores) {
NSLog(#"%lld", score.value);
//Add them all up here?
}
}
}];
}
You can make a variable outside of the loop, and in each iteration, var+=score.value. Therefore after the iteration, the variable you build will contain the total score.