2012年2月19日日曜日

TwitterFrameworkの利用


4 - Twitter Frameworkの利用

iOS5になってから、iOS上で簡単にTwitterAPIを利用することができるようになりました。
OAuth認証をしなくていいので、とても便利です。

そこで今回はこのTwitterFrameworkを利用して自分のタイムラインを取得したり、投稿してみたりします。

準備しておくもの:Twitterのアカウント

今回の流れ
  • プロジェクトの準備
  • タイムラインの取得
  • タイムラインをUITableViewに表示
  • Twitterへ投稿
です。
ちなみに次回は、この辺をこまごまと改良して、よりそれっぽいクライアントを作っていく予定です。



プロジェクトの準備
それではまず、プロジェクトの準備です。
いつも通り、NewProjectから進み、今回はMaster-Detail Applicationをテンプレートとして選択します。
Device FamilyはiPhone
Use Automatic Reference Countingを今回はオンにしましょう。

プロジェクトの設定画面が出て来たら、次はフレームワークを追加します。
前回と同様にLinked Frameworks and Librariesから
  • AccountFramework
  • TwitterFramework
の二つを追加します。

多分こんな画面になってると思います。
これでプロジェクトの準備は完了です。

TwitterFrameworkはiOSでTwitterを使うときに用いるライブラリ、
AccountFrameworkは、iOSがTwitterのアカウントとかNotification Centerの制御をしてますが、それを一元管理・利用するFrameworkです。多分。

MasterViewController.hでクラス変数の追加などを行います。
まず、二つのヘッダファイル
  • Accounts/Accounts.h
  • Twitter/Twitter/h
を追加します。




今回のクラス変数は
  • つぶやきのユーザー名とその内容を保存しておくための配列、
  • アカウントに関する情報にまつわるもの
を追加します。
さらに、クラスメソッドとして、タイムラインを読み込んで配列にデータを追加するメソッド loadTimeline を追加します。

MasterViewController.h
は次のようになります。



タイムラインの取得
それでは実際にTwitterのAPIを叩いてタイムラインを取得しましょう。
viewDidLoadメソッドを以下のように書き換えます。
- (void)viewDidLoad
{
    [super viewDidLoad];

accountStore = [[ACAccountStore alloc] init];
accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
userNameArray = [[NSMutableArray alloc] initWithCapacity:0];
tweetTextArray = [[NSMutableArray alloc] initWithCapacity:0];
[self loadTimeline];
}


ここではクラス変数の初期化を行っています。本来はinitメソッドでやるべきだとは思います。
その後に、loadTimelineでタイムラインを読みに行っています。


ではそのloadTimelineを実装しましょう


- (void)loadTimeline{
 
 [accountStore requestAccessToAccountsWithType:accountType
       withCompletionHandler:^(BOOL granted, NSError *error) {
        if (granted) {
         
         if (account == nil) {
          NSArray *accountArray = [accountStore accountsWithAccountType:accountType];
          account = [accountArray objectAtIndex:0];
         }
        
         if (account != nil) {
          NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.json"];
          NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
          [params setObject:@"20" forKey:@"count"];
          [params setObject:@"1" forKey:@"include_entities"];
          [params setObject:@"1" forKey:@"include_rts"];
          
          TWRequest *request = [[TWRequest alloc] initWithURL:url
                     parameters:params
                     requestMethod:TWRequestMethodGET];
          [request setAccount:account];
          [request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
           
           if (responseData) {
            NSError *jsonError;
            NSArray *timeline = [NSJSONSerialization JSONObjectWithData:responseData
                         options:NSJSONReadingMutableLeaves error:&jsonError];
            NSLog(@"%@", timeline);
           }
           
          }];
          
          
         }
         
         
        }
       }];
 
}


長いし、変な形してるしで大変ですが、
まずは

[accountStore requestAccessToAccountsWithType:accountType
withCompletionHandler:^(BOOL granted, NSError *error) {
     /*   コード  */
}];

では、アカウントストアの機能を使ってTwitterへリクエストを実行できるように認証を行ってます。
認証で、実行するのに時間を要するので、ここで処理を止めると他の機能へ支障が出てしまうかもしれません。
なので、ここではメソッドを実行して認証待ちを行い、その結果を受けた処理は別スレッドで行います。
その処理内容が 
withCompletionHandler:^(BOOL granted, NSError *error) {
/*   コード  */
}];
の部分です。


if (account == nil) {
NSArray *accountArray = [accountStore accountsWithAccountType:accountType];
account = [accountArray objectAtIndex:0];
}

この部分は利用するアカウントを取得しています。
accountArrayには、利用可能なアカウントが配列として格納されていて、今回はその中の一つ目のアカウントを利用します。

APIコールを行うURLとそのパラメータを設定します。
NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.json"];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:@"20" forKey:@"count"];
[params setObject:@"1" forKey:@"include_entities"];
[params setObject:@"1" forKey:@"include_rts"];
TWRequest *request = [[TWRequest alloc] initWithURL:url
  parameters:params
requestMethod:TWRequestMethodGET];
[request setAccount:account];


WebアプリケーションのAPIはHTTPを利用して情報の投稿と取得を行います。
そのリクエストをHTTPリクエストと呼びます。HTTPリクエストにはいくつかの種類やパラメータがありますが、
基本的にはurlとメソッドを定義してリクエストを投げます。
今回用いるURLは
http://api.twitter.com/1/statuses/home_timeline.json
です。
このURLにブラウザでアクセスしても多分アクセスできないと思います。
今回はURLで自分のタイムラインを取得するようにしています。

次にパラメータを設定します。ここで用いているNSMutableDictionary型は
いわゆるハッシュや連想配列とよばれているもので、キーを指定してオブジェクトを追加して行きます。


がその追加の例です。キーのcountはタイムラインで取得する件数のことで、今回は20件としています。
他の条件については
で確認できます。

TWRequest *request = [[TWRequest alloc] initWithURL:url
  parameters:params
requestMethod:TWRequestMethodGET];

では、リクエストを生成しています。
さらにその後でアカウントをセットしてリクエストの生成は完了です。


[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (responseData) {
NSError *jsonError;
NSArray *timeline = [NSJSONSerialization JSONObjectWithData:responseData
options:NSJSONReadingMutableLeaves error:&jsonError];
NSLog(@"%@", timeline);
}
}];

でリクエストを実行し、タイムラインを取得します。
perfomeRequestWithHandlerメソッドで、リクエストを実行します。
その結果はresponceDataに入っています。
この形式はJSONと呼ばれる形式で取得しているので、アクセスのしやすい形に整形します。
これを自動的にやってくれるメソッドが
NSJSONSerialization JSONObjectWithData: options: error:

です。

この結果をNSLogで出力すると、多分自分のタイムラインがずらーっと出力されます。







タイムラインをUITableViewに表示
このままだと扱いにくいので、データをクラス変数に突っ込んで行きます。
NSLogで出力した部分を次のように変更します。

for (NSDictionary *tweet in timeline) {
 [tweetTextArray addObject:[tweet objectForKey:@"text"]];
 NSDictionary *user = [tweet objectForKey:@"user"];
 [userNameArray addObject:[user objectForKey:@"screen_name"]];
}
[self.tableView reloadData];

先ほどのJSONObjectWithDataメソッドの返り値のデータ構造は、配列の各要素にツイートの内容が納められています。
この結果を一つ一つ取り出して、tweetTextArrayとuserNameArrayに入れて行きます。
見慣れないfor文は、Objetcive-Cにある文法の一つで、配列の各要素にたいして処理を行うことのできるものです。

ツイートの入っている配列の各要素は中身がNSDictionary型です。
ツイートの内容はキーがtextNSString型で取り出すことができます。
ユーザー情報はuserNSDictionary型で取り出し、さらにキー値をscreen_nameで取り出すことができます。

すべてのデータを取り出した後は、テーブルビューのデータを再読み込みして表示します。


データを突っ込んだ後は、テーブルビューに表示する内容を作りましょう。

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
 return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
 return [userNameArray count];
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

    }

 // Configure the cell.
 cell.textLabel.text = [userNameArray objectAtIndex:indexPath.row];
 cell.detailTextLabel.text = [tweetTextArray objectAtIndex:indexPath.row];
 
    return cell;
}


numberOfSectionsInTableView
ではテーブルビューのセクション数を返します。今回は1で。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
では何個セルがあるかを返します。今回はツイートの数だけなので、userNameArrayかtweetTextArrayの数を返します。
countメソッドかプロパティで値を返すことができます


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
では結果を表示して行きます。
cellのスタイルはUITableViewCellStyleSubtitleとします。これはメイン、サブ二種類のテキストを貼付けることができます。
貼付けは以下のように行います。

cell.textLabel.text = [userNameArray objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [tweetTextArray objectAtIndex:indexPath.row];



これで実行すると次のようにタイムラインを表示することができます。



Twitterへ投稿
これは今回の宿題としましょう。
updateTimelineと同じように投稿できます。もちろん部分部分は異なりますが。
TWRequestMethodGETTWRequestMethodPOSTに変えたりで出来ます。



詳しくはここを参考にどうぞ!
https://dev.twitter.com/docs/ios/posting-images-using-twrequest


0 件のコメント:

コメントを投稿