忍者ブログ
プログラミングとか日常とかの覚書っぽいなにか
[40] [39] [38] [37] [36] [35] [34] [33] [32] [31] [30]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

引き続きGTMOAuthライブラリを使用したiOS5用Twitterクライアント作成の解説です。
今回はツイートの投稿の方法を解説します。


REST (Representational State Transfer) とTwitter API

RESTはWebアプリケーションに代表される分散ネットワークアプリケーションにおいて、主にHTTPを使用してネットワーク上のリソース(情報)にアクセスするソフトウェアアーキテクチャの1つ、またはそこで使われるインタフェース(API)の方式のことです。

といっても抽象的すぎてあいまいなので、Twitterの場合を例に取ってみましょう。

Twitter APIでは、以下のようないろいろな情報が「リソース」として管理されています。
  • 個別のツイート(Twitter APIではステータス(status)と呼ばれる)
  • 特定のツイートの集合であるタイムライン(timeline)
  • ユーザ情報(users)
  • フレンド情報(friendships)
  • お気に入り情報(favorites)

これらの情報は「URI」と呼ばれる識別子によって識別されます。
URLとほぼ同じようなものですが、URLが場所の識別子なのに対し、URIはさらに一般化されたリソースの識別子のことを示します。ただし、よく知られている「URL」や、「URLエンドポイント」という呼び方をすることも多いです。

Twitterでリソースにアクセスする(例えばツイートを投稿したり、タイムラインを取得したりする)には、アクセス対象リソースのURIに対してHTTPでアクセスをすることになります。

HTTPではアクセスの種類によって「GET」「POST」「PUT」「DELETE」というメソッド(操作)が定義されており、情報を取得する場合は「GET」を使用し、新しく作成する場合は「POST」を使用する、というようにメソッドを使い分ける必要があります。

例えばTwitter APIで自分のホームタイムラインを取得する場合には、

http://api.twitter.com/1/statuses/home_timeline.json

というURIに対して、HTTPの「GET」メソッドを使用してアクセスすることで、タイムライン情報を取得することができます。

いくつかのAPIではオプションパラメータを指定することができるようになっています。
HTTP GETにおいてパラメータを指定する場合、URIの後ろに「?」記号で区切って「パラメータ名=値」で指定します。パラメータが複数ある場合はそれぞれを「&」記号で区切ります。

URL?パラメータ1=値1&パラメータ2=値2&...

例えば、ホームタイムラインで先頭から最大10件の最新ツイートのみを取得したい場合には

http://api.twitter.com/1/statuses/home_timeline.json?count=10

というURIを使用することになります。


Twitter APIでは、上記のようなURI指定ではJSON形式の結果をHTTP応答として受け取りますが、「.json」の部分を「.xml」に変更することで、結果をXML形式で受け取ることもできます。

実際には、ここで指定したパラメータとは別にOAuth署名情報がパラメータとして追加されていなければなりません。ただし、以前にも説明した通り、その作業はGTMOAuthAuthenticationが行ってくれるので、私達は特に気にすることはないのですが。

一方、新しいツイートをポストする場合には、

http://api.twitter.com/1/statuses/update.json

というURIに対してHTTPの「POST」メソッドを使うことになります。

HTTP POSTの場合は新しい情報を渡す必要があるので必ずパラメータを指定することになりますが、GETメソッドの場合と異なり、GET以外のメソッド(POST, PUT, DELETE)ではパラメータをHTTP要求のBody部に含める必要があります。Body部に含めるデータはGETパラメータの場合と同じように

パラメータ=値

の形式です。複数ある場合は

パラメータ1=値1&パラメータ2=値2&...

とします。

このデータ形式は「application/x-www-form-urlencoded」と呼ばれるもので、この形式データを送るため、HTTP要求ヘッダに「Content-Type: application/x-www-form-urlencoded」が含まれるようにしなければいけません。これには NSMutableURLRequest オブジェクトの setValue:forHTTPHeaderField: メソッドを使うことになります。

また、パラメータの値自体に「=」記号や「&」記号が含まれていたとしたらデータが間違って解釈されてしまうであろうことは容易に想像がつくと思います。
そこで、パラメータとして渡される値を「URI符号化」と呼ばれる表現方法に変換して記述します。「URL符号化」「URLエンコード」などと呼ばれる場合もあります。

先ほどは説明を省きましたがGETメソッドのパラメータの値についても同様にURI符号化されている必要があります。

本来はパラメータの値だけでなく、パラメータ名についてもURI符号化の対象ですが、Twitter APIで使用されているパラメータ名は半角英数字とアンダースコアのみから成り、URI符号化を行ってもURI符号化する前と同じ文字列になるので、ここではあえてパラメータ名を符号化する必要はありません。また、パラメータの値についても、半角英数字でのみ構成されることがあらかじめ分かっている場合には、URI符号化の必要はありません。

GTMOAuthAuthentication クラスにはURI符号化を行う encodedOAuthParameterForString: というクラスメソッドが用意されているので、ここではそれを使用することにします。


ツイートの投稿

ツイート投稿を行うAPIは「POST statuses/update」で、上でも書いたように

http://api.twitter.com/1/statuses/update.json

というURIに対してHTTP POSTメソッドを使用します。

ツイート本文をパラメータ名「status」のパラメータ値としてHTTP要求のBody部に渡すことになります。
これには、NSMutableURLRequest オブジェクトの setHTTPBody: メソッドを使いますが、Bodyデータを NSData 型で準備する必要があるので、パラメータ情報「status=XXXX」(XXXXはURI符号化した本文)の文字列(NSString)を作成し、その文字列の dataUsingEncoding: メソッドを使用して NSData に変換して、これを渡すことにします。

// ツイート投稿要求
- (void)fetchPostTweet:(NSString *)text
{
    // 要求を準備
    NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/update.json"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

    // statusパラメータをURI符号化してbodyにセット
    NSString *encodedText = [GTMOAuthAuthentication encodedOAuthParameterForString:text];
    NSString *body = [NSString stringWithFormat:@"status=%@", encodedText];
    [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];

    // 要求に署名情報を付加
    [auth_ authorizeRequest:request];

    // 接続開始
    GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
    [fetcher beginFetchWithDelegate:self
                  didFinishSelector:@selector(postTweetFetcher:finishedWithData:error:)];
}

// ツイート投稿要求に対する応答
- (void)postTweetFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *)error
{
    if (error != nil) {
        // ツイート投稿取得エラー
        NSLog(@"Fetching statuses/update error: %d", error.code);
        return;
    }

    // タイムライン更新
    [self fetchGetHomeTimeline];
}

ツイート画面の作成

最後に、ツイートを入力するためのViewを作成して表示する処理です。

まず、新しく作成する画面のView Controllerクラスを定義しておきましょう。

Fileメニュー
→ File
→ iOS - Cocoa Touch
→ Objective-C class

と選択し、クラス名「TweetViewController」を入力し、基底クラス「UIViewController」を選択します。
これで TweetViewController.h と TweetViewController.m が作成され、その中で TweetViewController クラスが定義されます。




コーディングはいったんおいておいて、先にStoryboard上での操作です。
MainStroyboard.storyboard を開き、Object LibraryからView Controllerをキャンバス上にドラッグ&ドロップして配置します。Attributes Inspector上で、View ControllerのTitleを指定できますが、ここでは「Tweet」にしておきます。(説明の際の識別のためだけなので、何でも構いませんし、Titleが空のままでも問題ないです。)



Identity Inspector上でViewに対応するView Controllerクラスを指定します。ここでは、先ほど作成した TweetViewController を指定しておきます。



次に、Master Viewにツイート用のボタンを配置します。
同じくObject Library上から、 Bar Button Itemを探し、Master View上のNavigation Itemの右端部分にドラッグ&ドロップして配置します。そして、Attributes InspectorのIdentifierで「Compose」を選択して、表示アイコンを変更します。



このボタンの動作として、 Tweet Viewのモーダル表示を割り当てます。
追加したボタンをControlキーを押しながらクリック(トラックバッドなら2本指タップ)すると半透明のパネルが表示されるので、「Modal」の横にある丸から Tweet View Controllerまで、マウスでドラッグします。



これにより、Master ViewからTweet Viewへ矢印の線が追加されます。これは画面(scene, シーン)の遷移を意味する「segue(セグエ)」を視覚的に表現したものになっています。
あらかじめこのsegueの識別子を変更しておきます。Main ViewからTweet Viewへのsegueをクリックして選択し、Attributes InspectorのIdentifierに「showTweetView」と入力しておきます。



次に、Tweet View上に入力用の項目を、Object Libraryからドラッグ&ドロップで配置していきます。
  • Navigation Bar (Titleを「Tweet」に変更)
  • Bar Button Item (左側:Identifierを Cancel に変更)
  • Bar Button Item (右側:Identifierを Done に変更)
  • Text View (Textを空にしておく)


Text Viewのに入力されるテキストを取得する際にText Viewへの参照が必要になるので、Text Viewのインスタンス変数をTweetViewControllerに追加します。

エディタをAssistant Editor表示にして、右側にソースコードが表示されるようにします。Project Navigator上で、ファイルを通常のクリックで選択した場合には標準のエディタ(左側)に、Optionキーを押しながらクリックした場合にはアシスタントエディタ(右側)に表示されるので、Optionキーを押したまま TweetViewController.m を選択してソースを右側に表示した状態にします。

左側のStoryboardでTweet View上のText ViewをControl+クリック(または2本指タップ)し、表示される半透明パネルの「New Referencing Outlet」からマウスドラッグし、ソースの「@interface 〜 @end」の範囲内にドロップします。



すると、名前を入力するポップアップが出現します。ここでは「textView」という名前を指定してConnectボタンを押します。



これにより、プロパティを定義するコードが自動的に挿入されます。

@interface TweetViewController ()
@property (weak, nonatomic) IBOutlet UITextView *textView;

@end

@implementation TweetViewController
@synthesize textView;

次に、DoneボタンやCancelボタンが押されたときの動作を定義していきます。

ボタンを押したときの動作となると、先ほどのTweetViewへの遷移と同様に、Storyboard上でsegueを追加して行おうと考えてしまいがちですが、もし同じ方法でMasterViewへ遷移させると、最初に表示されていたMasterViewが表示されるのではなく、新しく別のMasterViewのインスタンスを生成してそれを表示する、という動作になってしまいます。

正しくは、コード上でTweetViewControllerの dismissModalViewControllerAnimated: メソッドによりTweetViewを閉じなければなりません。

そこで、あらかじめ TweetViewController は表示元(今回の場合は MasterViewController)への参照を delegate として保持しておき、DoneボタンやCancelボタンが押されたことを検出したら、delegate を介して表示元へ通知を行います。通知を受けた MasterViewController は TweetViewController の dismissModalViewControllerAnimated: を呼び出してビューを閉じるようにします。

ここで、 MasterViewController ではなく TweetViewController が直接自分自身の dismissModalViewControllerAnimated: を呼び出すこともできるのではないかと思うかもしれません。確かにそのようにすることも可能ですが、下記のAppleのコーディングガイドラインに従うならば、上のようにするべきです。

「表示されたView Controllerを閉じるときによく使われるアプローチは、表示した側のView Controllerに閉じさせる方法です。つまり、できる限り、そのView Controllerを表示したのと同じView Controllerが閉じるべきなのです。」


先ほどと同様に、今度はCancelボタンで上でControl+クリックし、今度は「Sent Action」の下の「selector」からマウスドラッグし、ソースの「@interface 〜 @end」の範囲内にドロップします。



先ほどと同様に名前を入力するポップアップが出現するので、ここでは「cancel」と入力してConnectを押します。



これにより、ボタンを押されたときに実行されるメソッドが自動的に追加されます。

@interface TweetViewController ()
@property (weak, nonatomic) IBOutlet UITextView *textView;
- (IBAction)cancel:(id)sender;

@end

@implementation TweetViewController
@synthesize textView;

...(中略)...

- (IBAction)cancel:(id)sender {
}
@end

この手順をDoneボタンに付いても同様に行い、 done: メソッドも作成します。

次に、TweetViewController に新しく delegate プロパティを追加します。ボタンが押された際にこのデリゲートにメッセージを送信するようにします。

TweetViewController.h を以下のように変更します。

@protocol TweetViewControllerDelegate;	// プロトコル先行宣言


@interface TweetViewController : UIViewController

@property (weak, nonatomic) id <TweetViewControllerDelegate> delegate;

@end


@protocol TweetViewControllerDelegate <NSObject>

- (void)tweetViewControllerDidCancel:(TweetViewController *)viewController;

- (void)tweetViewControllerDidFinish:(TweetViewController *)viewController
                             content:(NSString *)content;

@end


そして、TweetViewController.m も @implementation 以下を次のように変更します

@implementation TweetViewController
@synthesize textView;
@synthesize delegate;

...(中略)...

- (IBAction)cancel:(id)sender {
    [self.delegate tweetViewControllerDidCancel:self];
}

- (IBAction)done:(id)sender {
    [self.delegate tweetViewControllerDidFinish:self content:textView.text];
}
@end

これで、CancelボタンとDoneボタンが押されたときに、それぞれデリゲートに tweetViewControllerDidCancel: と tweetViewControllerDidFinish:content: メッセージが送信されるようになりました。

残すは、MasterViewController 側のコードのみです。まず、 MasterViewController が TweetViewControllerDelegate を採用するように変更します。

@interface MasterViewController : UITableViewController <UIAlertViewDelegate, TweetViewControllerDelegate>

@end

TweetViewがモーダル表示される際に prepareForSegue:sender: が呼ばれるので、識別子(identifierプロパティ)が「showTweetView」である場合には自分自身(self)をTweetViewController の delegate にセットします。そして、TweetViewでCancelおよびDoneが押された際の処理を、それぞれ tweetViewControllerDidCancel: および tweetViewControllerDidFinish:content: に記述します。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showTweetView"]) {
        [segue.destinationViewController setDelegate:self];
    }
}

// TweetViewでCancelが押された
- (void)tweetViewControllerDidCancel:(TweetViewController *)viewController
{
    // TweetViewを閉じる
    [viewController dismissModalViewControllerAnimated:YES];
}

// TweetViewでDoneが押された
-(void)tweetViewControllerDidFinish:(TweetViewController *)viewController
                            content:(NSString *)content
{
    // TweetViewを閉じる
    [viewController dismissModalViewControllerAnimated:YES];
    
    // ツイートを投稿する
    if ([content length] > 0) {
        [self fetchPostTweet:content];
    }
}

Cancel、Doneが押された場合ともに、モーダル表示されたTweet Viewを閉じるようにしています。Doneが押された場合は、受け渡されたテキストをツイートテキストとして、投稿する処理を実施しています。

今回はかなり長くなりましたが、以上でツイート処理を行う画面は完成です。


参考リンク

Twitter developers - REST API Resources (英語)
https://dev.twitter.com/docs/api

Twitter API 仕様書 日本語訳
http://watcher.moe-nifty.com/memo/docs/twitterAPI.txt

拍手

PR

コメント
hermes birkin 42 bags fake for women
Oh, now I see why I hashtagged #bitchdontkillmyvibe one time and didn’t get any likes…
hermes birkin 42 bags fake for women http://www.accessoires-mode.in/hermes-birkin-42-c2_7/
【2017/05/29 06:55】 NAME[hermes birkin 42 bags fake for women] WEBLINK[URL] EDIT[]


コメントフォーム
お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード
  Vodafone絵文字 i-mode絵文字 Ezweb絵文字


忍者ブログ [PR]
プロフィール
HN:
はむぱい
職業:
ソフト作ったりしてる人
Twitter
最新CM
[06/09 replica rolex oyster perpetual datejust]
[06/09 bracelets imitation cartier love]
[06/09 replica the oyster perpetual datejust]
[06/09 datejust rolex oyster perpetual]
[06/09 replica gold love bangle]
カレンダー
08 2017/09 10
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
ブログ内検索
あ~いい漢字