3. 現在位置周辺のコンビニを探し、地図上にピンを立てる
現在地周辺の地点情報を調べるために、YOLPの「ローカルサーチAPI」を利用します。
今回のアプリでは、「電話帳」カセットを指定して、「現在地周辺10km以内のコンビニ」を検索することにします。
それ以外にも、ローカルサーチでは「カセット」を指定することにより、さまざまなPOIを検索することができますので、過去の連載記事(「YOLP Hacks: ローカルサーチAPIの使い方 ~パラメーターを極める!」)なども参考にしていただき、パラメータを操作していろいろ試してみてください。
また、カセットは、「YOLP カセットギャラリー」から探すことができます。
3-1. JSONパース用のライブラリを読み込む
APIのレスポンスはJSON形式で受け取ることにして、JSONをパースするためのライブラリは「SBJson」を利用します。
SBJsonとは、New BSD Licenseで公開されているフリーのライブラリで、著作権の表示と、無保証、免責の条件を守れば、誰でも利用することができます。
現在の最新安定版SBJson3.0系をダウンロードし、zipファイルを解凍します。解凍したファイルのClassesフォルダ以下をプロジェクトに読み込ませます。
3-2. 「ローカルサーチAPI」アクセスクラス作成
次に、「ローカルサーチAPI」にアクセスするためのクラスを新規に作成します。
ファイルのタイプはObjective-C classで、親クラスはNSObjectを選択して、新規ファイルを作成してください。名前はYolpLocalSearchとします。
データ通信を行うため、YolpLocalSearch.hにNSURLConnectionDataDelegateプロトコルを設定します。
また、APIから取得したデータの処理をViewControllerで行わせるために、YolpLocalSearch.hでYolpLocalSearchDelegateプロトコルを宣言し、メソッドを追加します。
#import <Foundation/Foundation.h> @protocol YolpLocalSearchDelegate; //プロトコルを宣言 @interface YolpLocalSearch : NSObject<NSURLConnectionDataDelegate> { CGFloat _lat; CGFloat _lon; NSURLConnection *_connection; NSMutableData *_data; id _result; id<YolpLocalSearchDelegate> _delegate; NSError* _error; } @property (nonatomic,readonly) id result; @property (nonatomic,assign) id<YolpLocalSearchDelegate> delegate; @property (nonatomic,readonly) NSError *error; - (id) initWithLat:(CGFloat)lat Lon:(CGFloat)lon; - (BOOL) searchPointByLocation; - (BOOL) validate; @end // プロトコルのメソッドを宣言 @protocol YolpLocalSearchDelegate <NSObject> -(void)didFinishWithYolpLocalSearch:(YolpLocalSearch *)station; -(void)didFailWithYolpLocalSearch:(YolpLocalSearch *)station; @end
YolpLocalSearch.mでは、先ほどプロジェクトに追加したSBJsonのヘッダーファイルをインポートします。
ViewController.mから、緯度経度情報を付与した初期化メソッド- (id) initWithLat:(CGFloat)lat Lon:(CGFloat)lonを実行し、- (BOOL) searchPointByLocation;を呼ぶと、ローカルサーチAPIの検索が行われます。
APIのレスポンスは非同期で受け取り、データの受信が完了したらエラーチェックの後、-(void)didFinishWithYolpLocalSearch:(YolpLocalSearch *)stationに渡されます。
このメソッド内でJSONのパース処理が呼ばれ、APIのレスポンスはNSArrayとNSDictionary形式に変換されます。
#import "YolpLocalSearch.h" #import "JSON/SBJson.h" //SBJsonをインポート #define API_YOLPSEARCH @"http://search.olp.yahooapis.jp/OpenLocalPlatform/V1/localSearch" #define APPID_YOLPSEARCH @"<あなたのアプリケーションID>" #define CID_YOLPSEARCH @"d8a23e9e64a4c817227ab09858bc1330" // 電話帳カセットのカセットID @implementation YolpLocalSearch @synthesize result = _result; @synthesize delegate = _delegate; @synthesize error = _error; // 初期化 - (id)initWithLat:(CGFloat)lat Lon:(CGFloat)lon { self = [super init]; if (self) { _lat = lat; _lon = lon; _connection = nil; _data = nil; } return self; } - (void) dealloc { // インスタンス変数を開放する [_connection release]; [_data release]; [_error release]; _delegate = nil; [super dealloc]; } // 検索のトリガーとなるメソッド。このメソッドをViewControllerから実行する - (BOOL) searchPointByLocation { if(_connection){ return FALSE; } NSString *query = [NSString stringWithString:@"コンビニ"]; query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSString* sYolpUrl = [NSString stringWithFormat:@"%@?output=json&appid=%@&cid=%@&detail=full&group=gid&distinct=true&start=1&results=10&dist=10&sort=dist&lat=%f&lon=%f&query=%@", API_YOLPSEARCH, APPID_YOLPSEARCH, CID_YOLPSEARCH, _lat, _lon, query]; // ローカルサーチAPIのリクエストURLを作成 // NSURLオブジェクトからNSURLREquestオブジェクトを作成 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:sYolpUrl] cachePolicy:0 timeoutInterval:10]; _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; return YES; } //レスポンスのバリデーション -(BOOL)validate{ if(_result == nil){ if (_error == nil) { _error = [[NSError alloc] initWithDomain:@"YolpLocalSearchError" code:0 userInfo:nil]; } return FALSE; } return TRUE; } // サーバからレスポンスが送られてきたことを通知 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { //[super connection:connection didReceiveResponse:response]; // レスポンスのステータスをチェック NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if(httpResponse.statusCode < 400){ // 正常レスポンスであれば、変数をクリアする if (_data) { [_data release]; } _data = [[NSMutableData alloc] init]; }else{ // エラーであれば、接続を中断する [_connection cancel]; [_connection release]; _connection = nil; } if(httpResponse.statusCode >= 400){ _error = [[NSError alloc] initWithDomain:@"YolpLocalSearchError" code:httpResponse.statusCode userInfo:nil]; if ([_delegate respondsToSelector:@selector(didFailWithYolpLocalSearch:)]) { [_delegate performSelector:@selector(didFailWithYolpLocalSearch:) withObject:self]; } } } // サーバからダウンロードしたデータ(data)を通知 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if(_data){ [_data appendData:data]; } } // ダウンロードが完了したことを通知 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { [_connection release]; _connection = nil; NSString *tmpString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]; _result = [[tmpString JSONValue] retain]; // JSONをパースする [tmpString release]; if([self validate]){ if ([_delegate respondsToSelector:@selector(didFinishWithYolpLocalSearch:)]) { [_delegate performSelector:@selector(didFinishWithYolpLocalSearch:) withObject:self]; } }else{ if ([_delegate respondsToSelector:@selector(didFailWithYolpLocalSearch:)]) { [_delegate performSelector:@selector(didFailWithYolpLocalSearch:) withObject:self]; } } [_result release]; } //通信がエラーになったことを通知 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { if(_data){ [_data release]; _data = nil; } [_connection release]; _connection = nil; _error = [error retain]; if ([_delegate respondsToSelector:@selector(didFailWithYolpLocalSearch:)]) { [_delegate performSelector:@selector(didFailWithYolpLocalSearch:) withObject:self]; } } @end