GameKitを使ってLeaderboardでランキングデータを管理する


#Leaderboardって？
Appleが用意してくれているSNS機能で得点サーバーのようなものです。
ゲームのランキング情報のようなものに使うスコアデータをAppleが管理してくれるので、自分でサーバーを用意しなくても世界ランキング機能みたいなものを実現することが出来ます。
[かつおぶし](https://itunes.apple.com/us/app/katsuobushi/id1062296781?l=ja&ls=1&mt=8)というアプリの世界ランキング機能で使用しています。完成イメージを見たい方は是非DLしてみてください。

#下準備
まずはiTunesConnectでLeaderboardの使用登録をします。
ちょくちょくインターフェイスが代わるのでそのうち参考にならなく成りますが、2016年1月現在はiTunesConect->MyApp->機能->GameCenterにあります。

![Kobito.XFT2J8.png](https://qiita-image-store.s3.amazonaws.com/0/35642/5a41e399-0bad-ff23-dc70-9b616a1a6ae8.png "Kobito.XFT2J8.png")

Leaderboardってのがランキング管理をしてくれる箱のようなものです。
動作を確認したいだけならまずはシングルLeaderboardを選択してください。
色々と入力項目が有りますがアプリに合ったフォーマットを選択します。
タイムを競うレースゲームならTimeの昇順、得点系ならIntegerで降順みたいな感じです。
付加情報として以下の項目の入力を迫られるので分りやすいものを設定します。

|項目名              |意味    |
|:------------------|:------|
|Leaderboardの参照名 |iTunesConnect上で識別するためのただの名前。|
|Leaderboard ID    |アプリから参照するためのID。|

得点データにはローカリゼーションを一つ以上設定する必要が有ります。
たとえば数字はカンマ区切りにするのか？や、サフィックス（〜点、〜ポイント）を設定します。

設定が終わると、MyAppのGameCenter部分でLeaderboardの使用設定をしておきます。

![Kobito.xBgjPn.png](https://qiita-image-store.s3.amazonaws.com/0/35642/02b73705-c7a0-265a-4972-55ceae986e43.png "Kobito.xBgjPn.png")

これで下準備は完了です。

#実装
##認証
まずはログインしないといけません。認証処理はGameCenterの画面に委譲されて成否結果を受け取るコールバックを設定します。
`GKLocalPlayer.localPlayer().authenticateHandler`
認証プロセスが中断されるとviewControllerに表示すべきコントローラーが渡されてくるので表示してあげます。
認証プロセスが完了するとviewContorollerにnilが設定されるのでerrorの内容を見て後続処理を行います。

```swift:login
GKLocalPlayer.localPlayer().authenticateHandler = {
    (viewController, error) -> Void in
    if ((viewController) != nil) {
        someViewController!.presentViewController(viewController!, animated: true, completion: nil);
    } else {
        if (error != nil){
            whenNG()
        } else {
            whenOK()
        }
    }
}
```

##スコアデータの送信
ログインが成功すると、Leaderboardにスコアを送信できるようになります。
GKScoreオブジェクトを先だってiTuneStoreで作成したLeaderboardのIDで生成します。
valueにはそれぞれのスコアボードに合った型のデータを設定します。
スコアを設定したら`reportScores`でスコアを送信します。一度に複数のスコアを送信することが出来ます。送信処理が完了すると、`reportScores`に渡した関数がコールバックされれくるので、認証の時と同じように`error`の有無で成否判定します。

```swift:sendScore
let scoreReport = GKScore.init(leaderboardIdentifier: ("yourLeaderboardID"))
scoreReport.value = Int64(score)
GKScore.reportScores([scoreReport]) {
    error in
    if (error == nil) {
        whenOk()
    } else {
    	whenNg()
    }
}
```

##スコアデータの取得
送信されたスコアデータを表示してランキング情報を表示します。
GKLeaderboadオブジェクトを作成します。
identifierにLeaderboardのIDを設定します。

```swift:getScore
let leaderBoardRequest = GKLeaderboard.init()
leaderBoardRequest.identifier = "yourLeaderboardID"
leaderBoardRequest.playerScope = GKLeaderboardPlayerScope.Global
leaderBoardRequest.timeScope = GKLeaderboardTimeScope.AllTime
leaderBoardRequest.range = NSRange(location: 1,length: 10)
        
leaderBoardRequest.loadScoresWithCompletionHandler({
    scores, error in
    if (error == nil) {
        whenOk()
    } else {
        whenNg()
    }
})
```

playerScoreやtimeScope、rangeはスコアデータ取得のクエリです。

|プロパティ | 用途 |
|:---|:---|
|playerScore|全プレイヤーのスコアかプレイヤーのフレンドのみか |
|timeScope|スコアの登録日が今日、一週間以内、過去分全部か |
|range|ランキングの何位を取得するか。デフォルトは１〜２５位 |

こまかい事は[ここ](https://developer.apple.com/library/tvos/documentation/GameKit/Reference/GKLeaderboard_Ref/index.html#//apple_ref/doc/uid/TP40009584-CH1-SW12)に書かれています。
クエリを送信すると例によって結果はコールバックされてくるのでerrorの有無で成否判定します。取得に成功するとscoresにGKScoreがarrayで返ってくるので画面に表示するなりなんなりの加工をしてあげます。
こんな感じで取得できます。

```swift:score
score.player.alias
Int(score.value)
score.date
```

#最後に
これだけでAppleがスコア情報を預かってくれるので自サーバーを用意しなくてもよくなります。もちろん複雑な構造のデータは自サーバーを用意して独自に実装する必要がありますが、単純なスコアデータ程度ならこれで十分事足りてしまします。