2011年7月12日火曜日

UITableView のセクションヘッダー

UITableView のセクションヘッダーに関するメソッドは以下の3つ
  • – tableView:titleForHeaderInSection:
  • – tableView:viewForHeaderInSection:
  • – tableView:heightForHeaderInSection:
タイトルを変更するだけならtableView:titleForHeaderInSection: を実装すればよく、独自の View を表示したいなら tableView:viewForHeaderInSection: でヘッダーの高さを返し、tableView:heightForHeaderInSection: で表示したい UIView を返す。これで TableView のスクロールに追従する Viewを挿入できる。


2011年7月5日火曜日

GameCenter 以前の GameKit

GameKit はもともと iOS 3.0 の頃から実装されていた。この頃は Peer To Peer とボイスチャットのみを扱う物であった。サーバが提供されていなかったため、LAN または bluetooth 上のデバイスしか検出できず(サーバたてれば別とは思う)、当時の利用方法としては Game よりも目の前の相手へのデータの転送などに使われていたのではないでしょうか。これが iOS 4.1 になって GameCenter が追加され Game アプリを作成する上で非常に大きな存在となった。ちなみに、4.0 にも API は存在するけど 4.1 で大幅な変更が加えられたため利用できない。






Peer to Peer

GKSession


GKSession *session = [[GKSession alloc] initWithSessionID:@"hoge" displayName:nil sessionMode:GKSessionModePeer];
session.delegate = self; 
[session setDataReceiveHandler:self withContext:nil]; 
session.available = YES;
Delegate は以下の通り。available = YES すると相手の session:peer:didChangeState が呼び出される。
  • session:peer:didChangeState:
  • session:didReceiveConnectionRequestFromPeer:
  • session:connectionWithPeerFailed:withError:
  • session:didFailWithError:
setDataReceiveHandler:withContext: を実行しているので以下のメソッドも定義する必要がある。
  • receiveData:fromPeer:inSession:
相手の Peer ID が分かれば connectToPeer:withTimeout:、 acceptConnectionFromPeer:error: の流れで接続する。 相手先にデータを送るには sendDataToAllPeers:withDataMode:error: または sendData:toPeers:withDataMode:error: を使う。 ここでいくつか注意をドキュメントから抜粋。
  1. 一度に送れるデータのサイズは 87KB 以下。
  2. 1KB以下であると良好なパフォーマンスが得られる。
  3. モードはGKSendDataReliable なら受信が成功するまで繰り返し、GKSendDataUnreliable なら一度だけ送る。
    GKSendDataReliable でも大きなデータ(画像など)を送っているとデータの欠落などが発生しエラーも発生しないみたい(未確認)なので、うまくいかない場合は自分で送受信でチェックを入れる

サンプル GKRocket にある SessionManager クラスを使うといろいろとやってくれて便利。




GKPeerPickerController

次のコードだけで Bluetooth による Peer to Peer ネットワークを作成してくれる。デフォルトでは Bluetooth のみ対応だけど、connectionTypesMask を設定すれば LAN も探してくれる。

GKPeerPickerController*		picker;  picker = [[GKPeerPickerController alloc] init]; 
picker.delegate = self; [picker show]; 
あとはデリゲートで対応する。peerPickerController:sessionForConnectionType: で GKSession 作って返す必要があるからそれだけ注意。
  • peerPickerController:sessionForConnectionType:
  • peerPickerController:didConnectPeer:toSession:
  • peerPickerControllerDidCancel:
GKPeerPicker を使うと Bluetooth を ON にするダイアログを表示してくれるし、connect と accept も自動でやってくれるので楽チン。





Voice Chat

GKVoiceChatService


iOS4.1 からの GKVoiceChat と混同しない。GKVoiceChat もそうであるが、3G 環境などの Wi-Fi 以外の環境では動作しない。

setup

マイクとスピーカーを使うので AudioSession を扱う必要がある。AudioSession とは Device のマイクやスピーカーの状態や挙動を管理してくれる物で、サイレントモードで音を再生するかどうかを設定したりできる。
AudioSession には C の関数の他に AVFoundation クラスが用意されているの好きな方を使えば良い。
NSError *myErr;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setPreferredHardwareSampleRate:8000.0 error:&myErr];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&myErr];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&myErr];

[GKVoiceChatService defaultVoiceChatService].client = self; //GKChatServiceClient protocol
[[GKVoiceChatService defaultVoiceChatService] setInputMeteringEnabled:YES]; 
[[GKVoiceChatService defaultVoiceChatService] setOutputMeteringEnabled:YES];
client は (NSString*)participantID 定義してある必要がある。これによってチャット相手を識別するのだけど、GKSession と併せて使うことになるだろうから peerID を用いれば良い。
- (NSString *)participantID
{ 
	return self.session.peerID;
}



start chat service

startVoiceChatWithParticipantID:error: メソッドで相手を捜し出し invite メッセージを送ってくれる。
受ける側は voiceChatService:didReceiveInvitationFromParticipantID:callID: を実装して、中で acceptCallID:error: を呼べば良い。

これ以降は音声入力があると voiceChatService:sendData:toParticipantID: が呼ばれるので、中で GKSession の sendData:toPeers:withDataMode:error: で相手にデータを送る。
受ける側は receiveData:fromPeer:inSession:context: 内で GKVoiceChatService の receivedData:fromParticipantID: を呼べばスピーカーから音が出る。

ソースコード書いた方が早かったかな?GKRocket の中の SessionManager クラスがとても参考になる。