TreasureData + iOS SDK

## はじめに
TreausureDataにTreasureData社が提供している`iOS SDK`を用いてデータをアップロードする方法を記載します。`Objective-C`と`Swift`とのそれぞれの方法を記載します。
動作については`Xcode`の`iOS Simulator`で確認しました。

## 環境
以下環境情報になります。

* 開発環境: Mac OS X: 10.9.5
* Xcode: 6.0.1
* iOS Simulator: iPhone6 / iOS 8.0
* [TreasureData iOS SDK](https://github.com/treasure-data/td-ios-sdk TreasureData iOS SDK): 0.1.4 

## 前提条件
以下前提条件となります。

* Xcodeが動作する環境があること。
* TreasureData iOS SDKを組み込むプロジェクトがあること。
* TreasureDataアカウントを持っていること。

注：今回は日本版TreasureDataである`Yahoo!ビッグデータインサイト`に対して実施しました。AWS版のTreasureDataを利用の方はEndpointを読み替えて実施してください。

## Step:1 TreasureData iOS SDKのインストール
ここでは`TreasureData iOS SDK`のXcodeプロジェクトへの組み込み方法を記載します。

手順については既に[GitHub](https://github.com/treasure-data/td-ios-sdk GitHub)に記載されていますが、こちらにも記載しておきます。

### Step:1-1 CocoaPodsのインストール

```cocoapod:cocoapod
$ gem install cocoapods
``` 

### Step:1-2 TreasureDataリポジトリの追加

```cocoapod:add_repo
$ pod repo add td https://github.com/treasure-data/PodSpecs.git
``` 

### Step:1-3 Podfileの編集
`TreasureData iOS SDK`を組み込みたいXcodeプロジェクトのPodfileに以下を追加します。

```cocoapod:Podfile
pod 'TreasureData-iOS-SDK', '= 0.1.4'
```

Podfileがまだない場合は、Xcodeプロジェクトディレクトリ直下に`Podfile`というファイル名でファイル作成し、上記を追記します。

```cocoapod:example
$ ls -d /Users/hogehoge/Desktop/ios/TdFirstApp # Xcodeプロジェクトディレクトリ
/Users/hogehoge/Desktop/ios/TdFirstApp
$ cat /Users/hogehoge/Desktop/ios/TdFirstApp/Podfile # Podfile
pod 'TreasureData-iOS-SDK', '= 0.1.4'
```

### Step:1-4 Install

```
$ cd /Users/hogehoge/Desktop/ios/TdFirstApp
$ pod install
```

### Step:1-5 Xcodeプロジェクトの起動
Step:1-3で初めてPodfileを作成した場合は、設定を反映させるために以下のファイルをダブルクリックしてXcodeプロジェクトを起動します。

```cocoapod:start_xcode
/Users/hogehoge/Desktop/ios/TdFirstApp/TdFirstApp.xcworkspace
```

## Step2: WriteOnly API-Keyの取得
TreasureDataには以下二つの`API Key`が存在します。

* フルアクセス権限API-Key: DB作成、削除、テーブル作成、削除、クエリ、データアップロードを行うことができるAPI-Key
* WriteOnly API-Key: データアップロードのみを行うことが出来るAPI-Key

ここではデータアップロードのみ可能なWriteOnly API-Keyの取得方法を記載します。

### Step2-1: WebConsoleにログイン
[WebConsole](https://console-ybi.idcfcloud.com/users/sign_in WebConsole)にアクセスしてLog inします。

![signin_1.png](https://qiita-image-store.s3.amazonaws.com/0/46472/37e7420e-2402-301d-77fc-8bf1c124c478.png "signin_1.png")

### Step2-2: My Profile画面の表示
ヘッダメニュ > Account名 > My Profile
でMy Profile画面を表示させます。
![console_myprofile.png](https://qiita-image-store.s3.amazonaws.com/0/46472/f0650e34-4675-4325-cac5-d9e48d2c4c1c.png "console_myprofile.png")

### Step2-3: Show Keys

`API Keys`パネルでアカウントのパスワード入力後に`Show Keys`ボタンを押下します。

![console_getapi1.png](https://qiita-image-store.s3.amazonaws.com/0/46472/df64ea9a-2824-f999-9c2a-61780e1b84f7.png "console_getapi1.png")


### Step2-4: WriteOnly API-Keyの取得
これでWriteOnly API-Keyが表示されるはずです。
まだ取得していいなければ、`Create New`ボタンを押下して取得してください。

![console_getapi2.png](https://qiita-image-store.s3.amazonaws.com/0/46472/38a4515a-c814-0343-dd73-56f2e5596596.png "console_getapi2.png")

## Step3: アップロード先DB/TABLE作成
### Step3-1: WebConsoleにログイン
アップロード先となるDB/TABLEを作成します。
[WebConsole](https://console-ybi.idcfcloud.com/users/sign_in WebConsole)にアクセスしてLog inします。

![signin_1.png](https://qiita-image-store.s3.amazonaws.com/0/46472/37e7420e-2402-301d-77fc-8bf1c124c478.png "signin_1.png")

### Step3-2: DB作成
サイドメニュのDatabaseタブをクリックします。
![console_db_create_1_no_name.png](https://qiita-image-store.s3.amazonaws.com/0/46472/0eac0b61-7bc8-c0eb-e1b5-ede67102108d.png "console_db_create_1_no_name.png")

Database名を入力してCreateボタンを押下します。
ここでは、`ios_sdk_db`と入力します。
![console_db_create_2_no_name.png](https://qiita-image-store.s3.amazonaws.com/0/46472/f410c51c-8f45-6fba-607a-a1e4eda70f10.png "console_db_create_2_no_name.png")

### Step3-3: Table作成
続けて`ios_sdk_db`DB画面で`Create Table`ボタンを押下します。

![console_table_create_ios_1.png](https://qiita-image-store.s3.amazonaws.com/0/46472/64f31009-1d84-e26d-0657-055119085aba.png "console_table_create_ios_1.png")

そしてテーブル名を入力して`Create Table`ボタンを押下してテーブルを作成します。
ここでは`ios_sdk_table`としています。

![console_table_create_ios_2.png](https://qiita-image-store.s3.amazonaws.com/0/46472/f5133f46-4f05-5a87-9bd9-167406e3cafc.png "console_table_create_ios_2.png")




## Step4: Sampleプロジェクトの準備
`TreasureData iOS SDK`を埋め込むSampleプロジェクトを準備します。
今回のSampleプロジェクトは、単純なラベルとボタンを配置しただけのSimple Page Applicationプロジェクトを作成しました。
`Objective-C`と`Swift`でソースコードが異なるのでここではそれぞれのソースコードを記載します。

### Step4-Case-1: Objective-C

ソースの雛形。

```source_before:ViewConroller.m
//
//  ViewController.m
//  TdObjectApp
//
//  Created by hogehoge on 2014/10/10.
//  Copyright (c) 2014年 hogehoge. All rights reserved.
//
/* Main処理を行うクラス */

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *Label;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)CountUp {
    /* ボタンが押されたときに行う処理 */
}

@end
```

`iOS Simulator`上の表示内容。
`Button Sample`押下時に`(IBAction)CountUp`が呼び出されます。
![ios_objectivec_before.png](https://qiita-image-store.s3.amazonaws.com/0/46472/e409c0b0-0666-16f6-b3a2-d995d058fb33.png "ios_objectivec_before.png")

### Step4-Case-2: Swift 
ソースの雛形。

```source_before:ViewConroller.swift
//
//  ViewController.swift
//  TdFirstApp
//
//  Created by hogehoge on 2014/10/10.
//  Copyright (c) 2014年 hogehoge. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBOutlet weak var Label: UILabel!
    
    var value = "LabelSample"
    
    
    @IBAction func countUp() {
	/* ボタンが押されたときに行う処理 */
	}
}
```

`iOS Simulator`上の表示内容。
`Button Sample`押下時に`@IBAction func countUp()`が呼び出されます。

![ios_swift_before.png](https://qiita-image-store.s3.amazonaws.com/0/46472/e74d5f10-11bb-402b-f78f-218ef33736ae.png "ios_swift_before.png")

## Step5: TreasureData iOS SDKの埋め込み
Step3で作成したプロジェクトに`TreasureData iOS SDK`を埋め込んでいきます。

### Step5-Case-1: Objective-C
#### Step5-1: import
対象のヘッダファイルに以下を追加します。

```in_sdk:ViewController.h
#import "TreasureData.h"
```

#### Step5-2: ソース埋め込み
以下のようにソースを埋め込み`Button Sample`押下時にデータをTreasureDataにアップロードするようにします。

```source_after:ViewConroller.m
//
//  ViewController.m
//  TdObjectApp
//
//  Created by hogehoge on 2014/10/10.
//  Copyright (c) 2014年 hogehoge. All rights reserved.
//
/* Main処理を行うクラス */

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *Label;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    /* TreasureData Initialize */
    [TreasureData initializeApiEndpoint:@"https://mobile-ybi.jp-east.idcfcloud.com"]; // Endpointの設定
    [TreasureData initializeWithApiKey:@"xxxxxxea09d147de381c3fd23c47035132d5xxxxxx"]; // WriteOnly API-Keyの設定

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)CountUp {
    /* ボタンが押されたときに行う処理 */
    [[TreasureData sharedInstance] addEventWithCallback:@{ // データ準備
                                                          @"name": @"hogehoge",
                                                          @"age": @77,
                                                          @"comment": @"Objective C" //{"name":"hogehoge", "age": 77, "comment":"Objective C"}というデータをアップロードする。
                                                          }
                                               database:@"ios_sdk_db" // アップロード先DB名
                                                  table:@"ios_sdk_table" // アップロード先Table名
                                              onSuccess:^(){
                                                  NSLog(@"addEvent: success");
                                              }
                                                onError:^(NSString* errorCode, NSString* message) {
                                                    NSLog(@"addEvent: error. errorCode=%@, message=%@", errorCode, message);
                                                }];

    [[TreasureData sharedInstance] uploadEvents]; //データアップロード
}
```

注：本来ならもっとシンプルに以下のようなコードでアップロードしてくれるはずなのですが、私の場合はデータが空の状態でアップロードされてしまい、正常にアップロードできませんでした。

```code:simple_objective-c
    [[TreasureData sharedInstance] addEvent:@{
                                       @"name": @"hogehoge",
                                       @"age": @77,
                                       @"comment": @"Objective C"
                                   }
                                   database:@"ios_sdk_db"
                                      table:@"ios_sdk_table"];
	[[TreasureData sharedInstance] uploadEvents];
```

### Step5-Case-2: Swift
#### Step5-1: import
`TreasureData iOS SDK`はObjective-Cで書かれているので、そのままではSwiftプロジェクトに取り込むことはできません。
取り込むためには`${AppName}-Bridging-Header.h`に`TreasureData iOS SDK`のインポート設定を記載する必要があります。

##### Step5-1-1: ${AppName}-Bridging-Header.h作成
注：まだ`${AppName}-Bridging-Header.h`がない場合に実施してください。

```
Xcode > File > New > File...
```

を選択して、ファイルテンプレート画面を表示させます。

```
iOS > Source > Cocoa Touch Class
```

を選択してNextボタンを押下して、

```
Class: hogehoge
Subclass of: NSObject
Language: Objective-C
```

を入力してNextボタンを押下してください。
そして対象のプロジェクトを選択して`Create`ボタンを押下して、ファイルを作成してください。

その際に以下のダイアログが表示されるので`Yes`を選択してください。
そうすると、`${AppName}-Bridging-Header.h`が作成されます。

![ios_swift_objectivec.png](https://qiita-image-store.s3.amazonaws.com/0/46472/6d2ca1a8-18ac-9d06-9d9b-3ff7174c5cb6.png "ios_swift_objectivec.png")

##### Step-5-1-2: import
```import:${AppName}-Bridging-Header.h
#import "TreasureData.h"
```

#### Step5-2: ソース埋め込み
以下のようにソースを埋め込み`Button Sample`押下時にデータをTreasureDataにアップロードするようにします。

```source_after:ViewController.swift
//
//  ViewController.swift
//  TdFirstApp
//
//  Created by hogehoge on 2014/10/10.
//  Copyright (c) 2014年 hogehoge. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

		/* TreasureData Initialize */
        TreasureData.initializeApiEndpoint("https://mobile-ybi.jp-east.idcfcloud.com") // Endpointの設定

		TreasureData.initializeWithApiKey("xxxxxxea09d147de381c3fd23c47035132d5xxxxxx") // WriteOnly API-Keyの設定
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBOutlet weak var Label: UILabel!
    
    
    @IBAction func countUp() {
	/* ボタンが押されたときに行う処理 */
			TreasureData.sharedInstance().addEventWithCallback(["name":"hogehoge", "age": 77, "comment":"Swift"], database: "ios_sdk_db", table: "ios_sdk_table", onSuccess: {()-> Void in
            println("addEvent: success")
            },
            onError:
            {(errorCode, message) -> Void in
                println("addEvent: error. errorCode=\(errorCode) message=\(message)")
            }
        	) // データ準備
        TreasureData.sharedInstance().uploadEvents() // データアップロード
	}
}
```

注：本来ならもっとシンプルに以下のようなコードでアップロードしてくれるはずなのですが、私の場合はデータが空の状態でアップロードされてしまい、正常にアップロードできませんでした。

```code:simple_swift
    TreasureData.sharedInstance().addEvent(["name":"hogehoge", "age": 77, "comment":"Swift"],database: "ios_sdk_db", table: "ios_sdk_table")
	TreasureData.sharedInstance().uploadEvents()
```

## Step6: データアップロード確認

`iOS Simulator`上で`Button Sample`をそれぞれ押下したときの`ios_sdk_table`は以下となります。

```
$ td query -w -t hive -d ios_sdk_db "SELECT * FROM ios_sdk_table"
...省略....
+----------+-----+-------------+------------+                               
| name     | age | comment     | time       |
+----------+-----+-------------+------------+
| hogehoge | 77  | Objective C | 1413113712 |
| hogehoge | 77  | Swift       | 1413113916 |
+----------+-----+-------------+------------+
2 rows in set
$
```
注:CLIで取得しております。

## おわりに
本来の使い方としては、
[GitHub](https://github.com/treasure-data/td-ios-sdk GitHub)に書いているように、アプリケーション起動時にEndpoint、API-Keyを初期化しておき、各種イベント発生時にsharedInstanceを用いてデータをアップロードするのが正しいと思います。

```
- (void)applicationDidBecomeActive:(UIApplication *)application {
	[TreasureData initializeApiEndpoint:@"https://mobile-ybi.jp-east.idcfcloud.com"];
    [TreasureData initializeWithApiKey:@"your_api_key"];
}
```