CoreBluetooth で出来る事

# CoreBluetooth

## はじめに
* 登場人物  

| 人物 | 説明 |
| ---- | ---- |
| サーバー | データを保持しているデバイス |
| クライアント | データの読み書きリクエストをするデバイス |

* 用語紹介

| 用語 | 説明 |
| ---- | ---- |
| ペリフェラル | デバイスを発見してもらうための役割を行う |
| セントラル | デバイスを発見するための役割を行う |
| アドバタイズ | ペリフェラルがデバイスを発見してもらうために行う、自分を表すパケットデータの発信 |
| キャラクタリスティクス | サーバーが持つデータを読み書きする単位 |
| サービス | サーバーの機能ごとに１つ以上のキャラクタリスティクスを束ねたもの |
| パッシブスキャン | アドバタイジングデータを受信するのみ |
| アクティブスキャン | クライアントがサーバーにスキャン要求を行い、アドバタイジングデータに載りきらなかったデータを取得する |
| ブロードキャスター | 周囲のクライアントに非接続で情報を広報するサーバー（送れるのは20バイト程度までの少量データ） |
| サブスクライブ | セントラルがペリフェラルのキャラクタリスティクスの変更を受取れるようにすること |

* できる事
	* 動的に変わるデータの通信
	* データはバイトデータで渡さるため、どんなデータでも渡せる
	* セキュアなデータでも送れる
		* ペアリングが必要
		* 特に難しい実装しなくともフラグを設定しておくだけでペアリングフローを実施してくれる
	* UUID を知らなくてもスキャンすること自体は可能
		* 電力消費量的に未指定は非推奨
	* サービスの中にサービスを入れることも可能
		* included service
	* バックグラウンドでも動作する
		* デバイスの検知
			* ただしアクティブスキャンは出来ない
		* アドバタイズ発信
			* ただしローカルネームは送信されない
* 出来ないこと
	* お互いの位置を性格に把握すること
	* サーバーへの書き込みに21バイト以上送信すること
	* アドバタイズパケットには容量制限がある
		* 28 バイトまで
		* UUID は 16 バイトあるので１つしか入れられない
			* 収まらなかったサービス UUID はアクティブスキャンにて返却可能

## データ

* ペリフェラルがブロードキャストする際にキャラクタリスティクスに設定出来るデータ
	* UUID
		* 何のキャラクタリスティクスなのかを定義
	* プロパティ （論理和で指定可能）	
		* CBCharacteristicPropertyBroadcast
			* characteristicの値をブロードキャストする
		* CBCharacteristicPropertyRead
			* 読み込み可能
		* CBCharacteristicPropertyWriteWithoutResponse
			* レスポンスのない書き込みが可能
		* CBCharacteristicPropertyWrite
			* 書き込み可能
		* CBCharacteristicPropertyNotify
			* レスポンスがないノーティフィケーションを許可
		* CBCharacteristicPropertyIndicate
			* インディケーションを許可
				* インディケーションってなんだろう
		* CBCharacteristicPropertyAuthenticatedSignedWrites
			* 認証付き書き込みが可能
		* CBCharacteristicPropertyExtendedProperties
			* 拡張プロパティ
		* CBCharacteristicPropertyNotifyEncryptionRequired
			* ペアリングしたクライアントのみノーティフィケーション可能
		* CBCharacteristicPropertyIndicateEncryptionRequired
			* ペアリングしたクライアントのみインディケーション可能
	* パーミッション （論理和で指定可能）
		* CBAttributePermissionsReadable
			* 読み込みのみ
		* CBAttributePermissionsWriteable
			* 書き込みのみ
		* CBAttributePermissionsReadEncryptionRequired
			* ペアリングしたクライアントのみ読み込み可能
		* CBAttributePermissionsWriteEncryptionRequired
			* ペアリングしたクライアントのみ書き込み可能
	* 値
		* バイトデータを指定すればその値はキャッシュされ利用される（デリゲートが呼ばれない）
		* nil を指定すればその値はオンデマンドで要求される（デリゲートが呼ばれる）

* セントラルがスキャンしたて受信できるアドバタイジングデータ
	* Key - Value ペア
		* CBAdvertisementDataLocalNameKey
			* ローカルネーム
		* CBAdvertisementDataTxPowerLevelKey
			* ペリフェラルの送信電力 (dBm)
		* CBAdvertisementDataServiceUUIDsKey
			* パッシブスキャンで得られたペリフェラルのサービスUUIDリスト
		* CBAdvertisementDataOverflowServiceUUIDsKey
			* アクティブスキャンで得られたペリフェラルのサービスUUIDリスト
		* CBAdvertisementDataServiceDataKey
			* サービスに関連する任意のバイトデータ
			* 仕様が特定の製造会社に縛られない一般的なもので、Bluetooth SIGが承認したサービスの定義があるならこっちが使われる
		* CBAdvertisementDataManufacturerDataKey
			* ペリフェラルの設計製造会社が設定できる任意のバイトデータ
			* 仕様が製造業者が独自に定義したものならこっちが使われる
		* CBAdvertisementDataIsConnectable
			* 接続可能かのフラグ
		* CBAdvertisementDataSolicitedServiceUUIDsKey
			* スキャンする時に指定したサービスUUIDリスト
	* RSSI
		* 受信信号強度(Received Signal Strength Indicator)
		* RSSI と CBAdvertisementDataTxPowerLevelKey を用いるとおおよその距離が図れる
			* 計算式は知らない

## フロー
 1. (ペ)アドバタイズ開始
 * (セ)ペリフェラルをスキャン
 * (セ)発見したペリフェラルのアドバタイジング データを確認
 * (セ)ペリフェラルへ接続
 * (ペ)セントラルと接続
 * (セ)接続したペリフェラルに対してサービスの検索
 * (セ)サービスに対してキャラクタリスティクスの検索
 * (セ)キャラクタリスティクスへのデータの読み書き要求
 * (ペ)読み書き要求に対して処理実行
 * (セ)キャラクタリスティクスの変更通知設定
 * (ペ)変更のあったキャラクタリスティクスのノーティス
 * (セ)ペリフェラルと切断  
  
## 実装

### ペリフェラル
ペリフェラルとして動作するには**CBPeripheralManager**のインスタンスを生成し、**CBPeripheralManagerDelegate**を実装する。

#### 初期化

```
CBPeripheralManager
- (id)initWithDelegate:(id<CBPeripheralManagerDelegate>)delegate queue:(dispatch_queue_t)queue;
- (id)initWithDelegate:(id<CBPeripheralManagerDelegate>)delegate queue:(dispatch_queue_t)queue options:(NSDictionary *)options
```
 
**パラメータ**

* delegate
	* 処理移譲先
* queue
	* 処理を行うキュー
		* nil を渡すとメインキューで行われるため、処理が重い場合は別キューを指定する
* options
	* ペリフェラルマネージャーのオプション
		* CBPeripheralManagerOptionShowPowerAlertKey : NSNumber (Boolean)
			* BlueTooth がオフの場合にユーザーにアラートを表示するかどうか
		* CBPeripheralManagerOptionRestoreIdentifierKey : NSString
			* OSがリストアする時にペリフェラルマネージャーを特定するのに利用される
			
#### ステート変更

以下のデリゲートが呼ばれる

```
CBPeripheralManagerDelegate
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
```

**パラメータ**

* peripheral
	* 該当のペリフェラルマネージャー
		* state プロパティを見る
		
**state**

* CBPeripheralManagerStateUnknown
	* 初期値
* CBPeripheralManagerStateResetting
	* システムとの接続が一時的に切れた
* CBPeripheralManagerStateUnsupported
	* BLE のサーバに機能がない
* CBPeripheralManagerStateUnauthorized
	* BLE のサーバになる権限がない
* CBPeripheralManagerStatePoweredOff
	* BLE が OFF になっている
* CBPeripheralManagerStatePoweredOn
	* BLE が ON になっている
 
 
state プロパティが CBPeripheralManagerStatePoweredOn の時にアドバイタイズを開始する。
開始する際にサービスとキャラクタリスティクスの構築を合わせて行う。

#### キャラクタリスティクスとサービスの構築 ####

##### キャラクタリスティクスを作る

```
CBMutableCharacteristic
- (id)initWithType:(CBUUID *)UUID properties:(CBCharacteristicProperties)properties value:(NSData *)value permissions:(CBAttributePermissions)permissions
```

**パラメータ**

* UUID
	* このキャラクタリスティクスを特定する一意なUID
* properties
	* 上述のプロパティ
* value
	* 値のバイトデータ
* permissions
	* 上述のパーミッション
	
	
##### サービスを作る

```
CBMutableService
- (id)initWithType:(CBUUID *)UUID primary:(BOOL)isPrimary
```

**パラメータ**

* UUID
	* このサービスを特定する一意なUID
* isPrimary
	* プライマリーか否か。プライマリーに設定したものだけがセントラルから見える。
	* 非プライマリーとは、補助的なデータをペリフェラルマネージャーに登録すること。正直イミフ。
	
##### サービスにキャラクタリスティクスを設定する

```
CBMutableService
@property(retain, readwrite) NSArray *characteristics;
```
 
##### ペリフェラルマネージャーにサービスを登録する

```
CBPeripheralManager
- (void)addService:(CBMutableService *)service
```

**パラメータ**

* service
	* キャラクタリスティクスを登録したサービス
	
#### サービスの追加が完了

以下のデリゲートが呼ばれる

```
CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
* service
	* 追加されたサービス
* error
	* nil じゃない場合はエラー内容
	
#### アドバタイズ開始

```
CBPeripheralManager
- (void)startAdvertising:(NSDictionary *)advertisementData
```	

**パラメータ**

* adverdisementData
	* アドバタイズパケットに含めるデータ
	* セントラル側で取得できるデータは上述の通りだが、設定出来るのは以下の２種
		* CBAdvertisementDataLocalNameKey
		* CBAdvertisementDataServiceUUIDsKey
		
#### アドバタイズ開始完了 ####

以下のデリゲートが呼ばれる

```
CBPeripheralManagerDelegate
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
```		

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
* error
	* nil じゃない場合はエラー内容
	
#### セントラルからのリクエストに応答 ####

##### 読み込みリクエスト

CBMutableCharacteristic の value に nil を設定したものに対して読み込み要求を出すと
以下のデリゲートが呼ばれる

```
CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
* request
	* リクエストオブジェクト
	
リクエストオブジェクトの中にキャラクタリスティクスを特定する UUID が入っているのでそれで判別し、リクエストオブジェクトの value プロパティに値をセットすることでセントラルにデータが渡せる

##### レスポンスの返却

```
CBPeripheralManager
- (void)respondToRequest:(CBATTRequest *)request withResult:(CBATTError)result
```

**パラメータ**

* request
	* リクエストデリゲートで受け取ったリクエストオブジェクト
* result
	* 結果ステータス
		* CBATTErrorSuccess
		* CBATTErrorReadNotPermitted
		* and more

#### 書き込みリクエスト

```
CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
```	

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
* requests
	* リクエストオブジェクトの配列
	
リクエストオブジェクトの value プロパティを、対応するキャラクタリスティクスの value に設定する。
合わせて、アプリ内のストレージや表示などを変更する必要がある場合は変更を行う。

#### サブスクリバーへの通知

ペリフェラルがプロパティに通知を設定しているキャラクタリスティクスを公開していて、セントラルがそのキャラクタリスティクスに対してサブスクライブした場合には以下のようになる

1. サブスクライブ登録
2. サブスクライブ登録通知
3. データの更新をサブスクリバーに通知
4. 通知の受信


##### サブスクライブ登録通知

```
CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
* central
	* サブスクライブしたセントラル
* characteristic
	* サブスクライブ対象

通知するのにセントラルを知っておく必要があるので保持しておく

##### セントラルへの通知

```
CBPeripheralManager
- (BOOL)updateValue:(NSData *)value forCharacteristic:(CBMutableCharacteristic *)characteristic onSubscribedCentrals:(NSArray *)centrals
```

**パラメータ**

* value
	* 値
* characteristic
	* 変更対象のキャラクタリスティクス
* centrals
	* 通知対象セントラル
	* nil を指定するとサブスクライブしている全セントラルに通知される
	
通知に成功した場合は返り値は YES となるが、送信キューがいっぱいだったなどの場合には NO が返る。
この場合、再度利用可能になった場合には peripheralManagerIsReadyToUpdateSubscribers: が呼び出される。
つまり、レスポンスが NO だったら再送用の配列に入れておき、peripheralManagerIsReadyToUpdateSubscribers: の中で再度 updateValue を呼び出すようにするとよい。

##### 通知送信キュー利用可能

```
CBPeripheralManagerDelegate
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
	
必要であれば、この中で再度 updateValue を実行する

##### サブスクライブ解除通知

```
CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラルマネージャー
* central
	* サブスクライブしたセントラル
* characteristic
	* サブスクライブ対象

保持していたセントラルを破棄するのに用いる

#### アドバタイズ停止

```
CBPeripheralManager
- (void)stopAdvertising
```

### セントラル

#### 初期化

```
CBCentralManager
- (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate queue:(dispatch_queue_t)queue
- (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate queue:(dispatch_queue_t)queue options:(NSDictionary *)options
```

**パラメータ**

* delegate
	* 処理移譲先
* queue
	* 処理を行うキュー
		* nil を渡すとメインキューで行われるため、処理が重い場合は別キューを指定する
* options
	* セントラルマネージャーのオプション
		* CBCentralManagerOptionShowPowerAlertKey : NSNumber (Boolean)
			* BlueTooth がオフの場合にユーザーにアラートを表示するかどうか
		* CBCentralManagerOptionRestoreIdentifierKey : NSString
			* OSがリストアする時にセントラルマネージャーを特定するのに利用される

#### ステート変更

以下のデリゲートが呼ばれる

```
CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
```

**パラメータ**

* central
	* デリゲートを発生させたセントラルマネージャー
		* state プロパティを見る

**state**

* CBCentralManagerStateUnknown
	* 初期値
* CBCentralManagerStateResetting
	* システムとの接続が一時的に切れた
* CBCentralManagerStateUnsupported
	* BLE のクライアント機能がない
* CBCentralManagerStateUnauthorized
	* BLE のクライアント機能の権限がない
* CBCentralManagerStatePoweredOff
	* BLE が OFF になっている
* CBCentralManagerStatePoweredOn		
	* BLE が ON になっている
	
	
#### ペリフェラルを探す

```
CBCentralManager
- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs options:(NSDictionary *)options
```

**パラメータ**

* serviceUUIDs
	* 必要とするサービスを持つペリフェラルのみをスキャンする場合に指定する
	* nil を指定するとフィルタリングせずにすべてのペリフェラルをスキャンする
	* 電力消費量的に nil は非推奨
* options
	* スキャンオプション
		* CBCentralManagerScanOptionAllowDuplicatesKey : NSNumber (Boolean)
			* YES にすると、ペリフェラルからアドバタイズパケットを受信するたびにペリフェラル発見通知がされる
				* iBeacon のように非接続で電波強度のみを知りたい
				* ブロードキャストのデータを取得したい
			* NO にすると、最初の発見時のみ通知される
		* CBCentralManagerScanOptionSolicitedServiceUUIDsKey : NSArray <CBUUID>
			* スキャンするサービスのリストを指定する

#### ペリフェラルが見つかった

以下のデリゲートが呼ばれる

```
CBCentralManagerDelegate
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
```

**パラメータ**

* central
	* デリゲートを発生させたセントラルマネージャー
* peripheral
	* 発見したペリフェラル
* advertisementData
	* ペリフェラルの発信していたアドバタイズデータ
	* 内容については上述の通り
* RSSI
	* ペリフェラルの RSSI


以後、ペリフェラルとの接続や切断が必要になるため、peripheral は保持しておく

#### ペリフェラルに移譲先指定

スキャンして発見したペリフェラルに対して接続する際は、そのペリフェラルに対して移譲先を指定しておくことで、詳細に振るまいを指定することが可能となる

```
CBPeripheral
@property(weak, nonatomic) id<CBPeripheralDelegate> delegate
```

#### ペリフェラルとの状態を確認

すでに接続済みであるか等を確認する

```
CBPeripheral
@property(readonly) CBPeripheralState state
```

**state**

* CBPeripheralStateDisconnected
	* 未接続
* CBPeripheralStateConnecting
	* 接続中
* CBPeripheralStateConnected
	* 接続済み
	
	
#### ペリフェラルと接続

```
CBCentralManager
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options
```

**パラメータ**

* peripheral
	* 接続先ペリフェラル
* options
	* 接続オプション
		* CBConnectPeripheralOptionNotifyOnConnectionKey
			* アプリがサスペンドしている時にペリフェラルとの接続に成功した場合にアラートを表示させる
			* バックグラウンドモードに bluetooth-central を指定していない時に有効
		* CBConnectPeripheralOptionNotifyOnDisconnectionKey
			* アプリがサスペンドしている時にペリフェラルとの接続が切断された場合にアラートを表示させる
			* バックグラウンドモードに bluetooth-central を指定していない時に有効
		* CBConnectPeripheralOptionNotifyOnNotificationKey
			* アプリがサスペンドしている時にペリフェラルから通知がきた場合にアラートを表示させる
			* バックグラウンドモードに bluetooth-central を指定していない時に有効


#### ペリフェラルとの接続成功

ペリフェラルとの接続に成功した場合、以下のデリゲートが呼ばれる

```
CBCentralManagerDelegate
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
```

**パラメータ**

* central
	* デリゲートを発生させたセントラルマネージャー
* peripheral
	* 接続に成功したペリフェラル

#### ペリフェラルとの接続失敗

ペリフェラルとの接続に失敗した場合、以下のデリゲートが呼ばれる

```
CBCentralManagerDelegate
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
```

**パラメータ**

* central
	* デリゲートを発生させたセントラルマネージャー
* peripheral
	* 接続に失敗したペリフェラル
* error
	* nil じゃない場合はエラー内容

#### サービスの検索

```
CBPeripheral
- (void)discoverServices:(NSArray *)serviceUUIDs
```

**パラメータ**

* serviceUUIDs
	* 必要とするサービスの UUID リスト
	* nil を指定すると、全てのサービスが検索対象となる
	* 通信時間と処理時間がかかるので、なるべく nil は指定しない
	

#### サービスが見つかった

サービスの検索結果、発見できた場合は以下のデリゲートが呼ばれる

```
CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラル
* error
	* nil じゃない場合、エラー内容
	
CBPeripheral の services プロパティに発見したサービスリストが NSArray<CBService> として格納されている


####　キャラクタリスティクスの検索

見つかったサービスに対して、必要なデータのあるキャラクタリスティクスを検索する

```
CBPeripheral
- (void)discoverCharacteristics:(NSArray *)characteristicUUIDs forService:(CBService *)service
```

**パラメータ**

* characteristicUUIDs
	* 必要とするキャラクタリスティクスのUUID
	* nil を指定すると全てのキャラクタリスティクスが検索対象となる
	* 通信時間と処理時間がかかるので、なるべく nil は指定しない
* service
	* 検索対象のサービス


#### キャラクタリスティクスが見つかった

キャラクタリスティクスが見つかると、以下のデリゲートが呼ばれる

```
CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラル
* service
	* キャラクタリスティクスの見つかったサービス
* error
	* nil じゃない場合、エラー内容
	
#### ペリフェラルへリクエストの送信

##### 読み込みリクエスト

```
CBPeripheral
- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic
```

**パラメータ**

* characteristic
	* 読み込みたいキャラクタリスティクス

##### 読み込みレスポンス

キャラクタリスティクスに読み込みリクエストを送ると、以下のデリゲートが呼ばれる

```
CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラル
* characteristic
	* 読み込み対象のキャラクタリスティクス
* error
	* nil じゃない場合、エラー内容
	
characteristic の value プロパティに NSData 形式のバイトデータが格納されている  
ただし、キャラクタリスティクスのパーミッションで指定出来るものに上げたとおり、読み込み不可のものもあるため事前に確認しておくとよい

##### 書き込みリクエスト

```
CBPeripheral
- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type
```

**パラメータ**

* data
	* 書き込む内容（20バイトまで）
* characteristic
	* 書き込みたいキャラクタリスティクス
* type
	* 書き込みタイプ
		* CBCharacteristicWriteWithResponse
			* レスポンスが欲しい
		* CBCharacteristicWriteWithoutResponse
			 * レスポンスはいらない


##### 書き込みレスポンス

書き込み要求時に type として CBCharacteristicWriteWithResponse を指定した場合、以下のデリゲートが呼ばれる

```
CBPeripheralDelegate
 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
```
**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラル
* characteristic
	* 書き込んだキャラクタリスティクス
* error
	* nil じゃない場合は、エラー内容


##### キャラクタリスティクスの更新通知設定

キャラクタリスティクスのパーミッションでノーティフィケーションが可能である場合、以下を設定することでペリフェラル側で更新が発生するたびにそれを知ることができる

```
CBPeripheral
- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic
```

**パラメータ**

* enabled
	* YES : 通知を受取る
	* NO : 通知を受け取らない
* characteristic
	* 更新通知を設定したいキャラクタリスティクス

##### キャラクタリスティクスの更新通知取得

セントラルで setNotifyValue を行ったキャラクタリスティクスに対して、ペリフェラルで updateValue:forCharacteristic:onSubscribedCentrals: が実行されると、以下のデリゲートが呼ばれる

```
CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
```

**パラメータ**

* peripheral
	* デリゲートを発生させたペリフェラル
* characteristic
	* 更新が発生したキャラクタリスティクス
* error
	* nil じゃない場合は、エラー内容

#### セントラルマネージャーで保持しているペリフェラルリストの取得

```
CBCentralManager
- (NSArray *)retrievePeripheralsWithIdentifiers:(NSArray *)identifiers
- (NSArray *)retrieveConnectedPeripheralsWithServices:(NSArray *)serviceUUIDs
```

identifiers で指定したペリフェラルリストを取得  
serviceUUIDs を持っている接続済みペリフェラルリスト取得

#### ペリフェラルと切断

ペリフェラルとの通信が終わったら切断をする

```
CBCentralManager
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral
```

**パラメータ**

* peripheral
	* 切断したいペリフェラル

#### ペリフェラルと切断完了

ペリフェラルとの切断が完了すると、以下のデリゲートが呼ばれる

```
CBCentralManagerDelegate
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
```

**パラメータ**

* central
	* デリゲートを発生させたセントラルマネージャー
* peripheral
	* 切断したペリフェラル
* error
	* nil じゃない場合、エラー内容

#### スキャン停止

ペリフェラルのスキャンを停止

```
CBCentralManager
- (void)stopScan
```

## 最後に

せっかくの低消費電力で動作する BLE を利用しているので、アプリで大量に電力消費するようなことのないよう充分に気をつけてコーディングすることが重要である。  
iOS 同士の P2P に利用する目的であれば MultipeerConnectivity.framework を利用するのがよい。