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

