2011年5月24日火曜日

外部の関数を取り入れる場合のいろいろ

★ 外部の関数を取り入れる場合のいろいろ
json-framework
SimpleHttpClient
-----------------------------------------------------------------------------------
buildの設定のところで
    Link Binary With Libraries
        libxml2.dylib 追加する

    Other Linker Flags
        -xml2 を追加する

    Header Search Paths
        /usr/include/libxml2 を追加する

-----------------------------------------------------------------------------------
・SimpleHttpClient
    https://github.com/cooldaemon/SimpleHttpClient
  
    http://d.hatena.ne.jp/cooldaemon/20100122/1264137498#
    ↑大変ありがとうございます。

    ・DDXML+HTML
        https://gist.github.com/185012
——————————————————————————————————
・json-framework
    http://code.google.com/p/json-framework/
    単に"Classes"というfolderごとコピーする方法が簡単
    使いたいところで
    ・ #import "JSON.h"
-----------------------------------------------------------------------------------

・SimpleHttpClientの説明
    https://github.com/cooldaemon/SimpleHttpClient

    JSON と XML のフィルタを追加
    HTML フィルタも追加
    (HTML に対して XPath が使えます)

    NSOperationQueue を外部から与えられるようにしました。
    スレッドを管理するキューは、
    一つの iPhone アプリに対して、一つで十分

-----------------------------------------------------------------------------------

・テストコードの解説

    ・初期化
    SimpleHttpClient *client = [[SimpleHttpClient alloc] initWithDelegate:self];

    まずは、SimpleHttpClient のオブジェクトを作ります。
    引数として delegate を渡していますが、
    リクエスト毎に delegate を変更する事も出来ます。

-----------------------------------------------------------------------------------

    ・GET リクエスト
    例えば、下記のような GET リクエストを発行したいとします。
    http://foo.bar/search?q=iphone&q=osx&lr=lang_en

    その場合は、下記のような辞書オブジェクトを作成し・・・
    NSMutableDictionary *params = [NSMutableDictionary
        dictionaryWithObject:[NSArray arrayWithObjects:@"iphone", @"osx", nil]
                      forKey:@"q"
    ];
  
    [params setObject:@"lang_en" forKey:@"lr"];

    辞書オブジェクトを JSON 風に表現すると下記のような感じです。
    {
        q  : ['iphone', 'osx'],
        lr : 'lang_en'
    }

    Value は、NSArray と NSString 以外は無視されます。
    これを、先ほど作成した SimpleHttpClient のオブジェクトに登録します。

    [client
               get        :@"http://foo.bar/search"
        parameters    :params
           context    :@"iphone"
    ];

    context は、後ほど説明します。

    この時点で、別スレッド上で GET リクエストが実行されます。
    実際には、負荷が高ければキューに積まれ、
    負荷が下がるのを待ってから実行されるのですが、
    この辺りは、NSOperation と NSOperationQueue 任せです。

-----------------------------------------------------------------------------------
    ・POST リクエスト
    上記の 'get' を 'post' に変更します。

    [client
                post    :@"http://foo.bar/search"
        parameters    :params
               context    :@"iphone"
    ];

-----------------------------------------------------------------------------------
    ・データの受信
    NSURLConnection でよく使われるメソッドだけラップしてあります。
    気をつけるべき点は、別スレッドで同時に動いているので、
    一つの delegate にメッセージが集中する事です。

    (リクエスト時、個別に delegate を指定した場合は別です。)
    その為、リクエスト時に指定した context を利用して処理を分岐させます。

    例えば、didReceiveResponse を受け取る場合は、下記のようにします。

    - (void)simpleHttpClientOperation:(SimpleHttpClientOperation *)operation
        didReceiveResponse:(NSHTTPURLResponse *)response
    {
            [_response setObject:response forKey:operation.context];
    }

    operation.context には、
    リクエストを登録する際に引数として渡した context が入っています。
    これを利用して、処理を分岐させて下さい。


-----------------------------------------------------------------------------------
    その他
    GET、POST 共に priority を指定できます。
    緊急度の高いリクエストを優先的に行ったり、
    暇な時に行えば良いリクエストを後回しにしたりできます。

    詳細は、NSOperation のマニュアルをご参照ください。



-----------------------------------------------------------------------------------
    iPhone アプリのサンプルプロジェクト
    http://github.com/cooldaemon/TestSimpleHttpClient

-----------------------------------------------------------------------------------
    ・SimpleHttpClient に JSON と XML のフィルタ

    WSSE に対応した際と同じくドメイン毎にフィルタを設定できるので、
    reader.livedoor.com から取得したデータは JSON フィルタを通す、
    b.hatena.ne.jp から取得したデータは XML フィルタを通す
    ・・・という使い方が可能です。

    具体的には、下記のように設定を行ないます。

    SimpleHttpClient *client = [[[SimpleHttpClient alloc] initWithDelegate:self] autorelease];

    [client
        setFilter    :SimpleHttpClientFilterJSON
        forHost    :@"reader.livedoor.com"
    ];

    [client
        setFilter    :SimpleHttpClientFilterXML
        forHost    :@"b.hatena.ne.jp"
    ];

    もし、http://reader.livedoor.com/api/subs に対してリクエストを送ったのであれば、
    フィルタ済みのデータを受け取るには下記のようにします。

    - (void)simpleHttpClientOperationDidFinishLoading
                        :    (SimpleHttpClientOperation *)operation
        filteredData    :    (id)data
    {
        _subs = (NSArray *)[data retain];
    }

    http://reader.livedoor.com/api/subs は、Array 型の JSON を返すので NSArray * にキャストします。

    data は autorelease 済みであり、
    simpleHttpClientOperationDidFinishLoading:filteredData:
    メッセージは、サブスレッドの中で呼ばれるので、retain しておかないと、
    サブスレッド終了時に NSAutoreleasePool に release されてしまいます。

-----------------------------------------------------------------------------------
    ・SimpleHttpClient に KissXML+HTML を組み込んだHTML フィルタ

    下記のように、SimpleHttpClient のオブジェクトを作成し・・・

    SimpleHttpClient *client = [[SimpleHttpClient alloc] initWithDelegate:self];

    HTML 用のフィルタを設定し・・・

    [client
        setFilter:SimpleHttpClientFilterHTML
          forHost:@"d.hatena.ne.jp"
    ];

    リクエストを送ると・・・

    [client
          get            :@"http://d.hatena.ne.jp/cooldaemon/20090911/1252637257"
        parameters    :nil
          context    :nil
    ];
  
    DDXMLDocument のオブジェクトが受け取れます。

    - (void)simpleHttpClientOperationDidFinishLoading:(SimpleHttpClientOperation *)operation
                                     filteredData:(id)data
    {
        [_html release];
        _html = (DDXMLDocument *)[data retain];
    }

    XPath を使うには、下記のようにします。

    NSError *error = nil;
    NSArray *body = [_html
        nodesForXPath:@"id(\"days\")//div[@class=\"body\"]//h3/following-sibling::*|id(\"days\")//div[@class=\"body\" and not(.//h3)]"
            error:&error
    ];

    NSLog("%@", [body componentsJoinedByString:@""]);
        詳しくは、test/TestHatenaDiaryHTML.mを参照

0 件のコメント: