Yahoo!ジオコーダAPIについて
キーワード入力画面ができたら、次はキーワードをもとにYahoo!ジオコーダAPIにアクセスして、結果一覧を表示する画面を作ります。
が、その前にYahoo!ジオコーダAPIについて簡単に説明しようと思います。
Yahoo!ジオコーダAPIは、キーワードとして住所を渡すと、該当する住所の候補に、緯度経度を付与した形で返すことができます。
アクセスする一例としては、以下のようなURLです。
(queryは「東京都新宿区舟町5」をURLエンコードしたもの)
http://geo.search.olp.yahooapis.jp/OpenLocalPlatform/V1/geoCoder?appid=<準備したアプリケーションID>&ei=utf-8&query=%E6%9D%B1%E4%BA%AC%E9%83%BD%E6%96%B0%E5%AE%BF%E5%8C%BA%E8%88%9F%E7%94%BA5
上記アクセス例のappidの内容を、用意したアプリケーションIDに書き換えてアクセスをすると、以下のようなレスポンスが返ってくるはずです。
<YDF xmlns="http://olp.yahooapis.jp/ydf/1.0" totalResultsReturned="6" totalResultsAvailable="6" firstResultPosition="1"> <ResultInfo> <Count>6</Count> <Total>6</Total> <Start>1</Start> <Status>200</Status> <Description/> <Copyright/> <Latency>0.067</Latency> </ResultInfo> <Feature> <Id>13104.81.5</Id> <Gid/> <Name>東京都新宿区舟町5</Name> <Geometry> <Type>point</Type> <Coordinates>139.72146148,35.68966308</Coordinates> <BoundingBox>139.67325872,35.67310100 139.74524627,35.72989744</BoundingBox> </Geometry> <Category/> <Description/> <Style/> <Property> <Uid>20c0626a247e0a80a9267e3f20892e6dd99e264b</Uid> <CassetteId>b22fee69b0dcaf2c2fe2d6a27906dafc</CassetteId> <Yomi>トウキョウトシンジュククフナマチ</Yomi> <Country> <Code>JP</Code> <Name>日本</Name> </Country> <Address>東京都新宿区舟町5</Address> <GovernmentCode>13104</GovernmentCode> <AddressMatchingLevel>5</AddressMatchingLevel> </Property> </Feature> <Feature> <Id>13104.81.5.8</Id> <Gid/> ----- 中略 ----- </Feature> </YDF>
YOLPのAPIで得られる内容は、標準データフォーマットとして定義された、YDF(YOLP Data Format)と呼ばれるフォーマットで返されます。
YDFについての詳しい情報は以下をご覧ください。
Yahoo!ジオコーダAPIでは、取得した住所候補の一つが、YDFで定義されているFeature要素の一つとして扱われます。Feature要素の中には、住所名やその住所を示す緯度経度などがまとめて含まれています。
なおAPIはパラメータ指定をすることで、XMLの他にJSONの形でもレスポンスを返すことができます。
住所候補リストアップ画面の作成
さていよいよ画面を作ります。大まかな流れは以下のとおりです。
- 初期化の際にキーワードを取得する
- 基本的な画面生成を行う
- 画面生成後、キーワードをもとにYahoo!ジオコーダAPIにアクセスする(JSONでレスポンスを返すように指定する)
- Yahoo!ジオコーダAPIからレスポンスを取得したら、内容を解析し画面を更新して、住所候補を一覧表示する
この流れを、使用するクラスと合わせると以下のようになります。
- 一覧表示のためにUITableViewControllerをサブクラスとし、キーワードを受け取るイニシャライズのメソッドを用意する
- UITableViewControllerのviewDidLoadedでYahoo!ジオコーダAPIにアクセスするためにNSURLConnectionを使う
- APIから取得した内容を解析するためにNSJSONSerializationを使う
- 解析完了後、その内容をUITableViewControllerのtableViewに反映すべく、reloadDataを実行する
[File]-[New]-[New File](Xcode4.3では[File])を選んで、新しいファイルのテンプレート選択画面を出します。
テンプレートは「UIViewController subclass」(Xcode4.3では「Objective-C class」)を選んで、クラス名はGeoCodingViewController、サブクラスはUITableViewControllerでファイルを作ります。
#import <UIKit/UIKit.h>
@interface GeoCodingViewController : UITableViewController {
NSString *_keyword;
NSURLConnection *_connection;
NSMutableData *_data;
NSArray *_resultList;
}
- (id)initWithKeyword:(NSString *)keyword;
@end
#import "GeoCodingViewController.h"
#define APP_ID @"<準備したアプリケーションID>"
@implementation GeoCodingViewController
- (id)initWithKeyword:(NSString *)keyword {
self = [super initWithStyle:UITableViewStylePlain];
if (self) {
_resultList = nil;
_connection = nil;
_data = nil;
_keyword = [keyword retain];
}
return self;
}
- (void)dealloc {
if(_connection){
[_connection cancel];
[_connection release];
}
[_data release];
[_resultList release];
[_keyword release];
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"検索結果";
if(_resultList == nil){
//表示するリストデータが無ければ、APIに通信して取得する
NSMutableArray *paramList = [[NSMutableArray alloc] init];
[paramList addObject:[NSString stringWithFormat:@"appid=%@",APP_ID]];
[paramList addObject:@"ei=utf-8"];
[paramList addObject:@"output=json"];
[paramList addObject:@"results=50"];
NSString *encodedQuery = [_keyword stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[paramList addObject:[NSString stringWithFormat:@"query=%@",encodedQuery]];
NSString *urlPath = [NSString stringWithFormat:@"http://geo.search.olp.yahooapis.jp/OpenLocalPlatform/V1/geoCoder?%@",[paramList componentsJoinedByString:@"&"]];
[paramList release];
NSLog(@"%@",urlPath);
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.title = @"検索中";
}
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return (_resultList == nil) ? 0 : 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return (_resultList == nil) ? 0 : [_resultList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"AddressCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *target = [_resultList objectAtIndex:indexPath.row];
cell.textLabel.text = [target objectForKey:@"Name"];
cell.detailTextLabel.text = [[target objectForKey:@"Property"] objectForKey:@"Yomi"];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
#pragma mark - NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
self.tableView.tableHeaderView = nil;
[_connection cancel];
[_connection autorelease],_connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if(_data){
[_data release];
}
_data = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSError *jsonError = nil;
id result = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingAllowFragments error:&jsonError];
_resultList = [[result objectForKey:@"Feature"] retain];
self.title = @"検索結果";
if([_resultList count]>0){
[self.tableView reloadData];
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:self.title
message:@"指定のキーワードでは見つかりませんでした。"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
[_data release],_data = nil;
[_connection autorelease],_connection = nil;
}
@end
これで住所候補リストアップ画面ができます。
次に、この画面を呼び出すために、キーワード入力画面のプログラムを少しだけ書き換えます。
#import "RootViewController.h"
//作成したリストアップ画面を使えるようにimport文を追加
#import "GeoCodingViewController.h"
@implementation RootViewController
----- 中略 -----
- (BOOL)submit{
[_textField resignFirstResponder];
//インスタンス生成、nagivationControllerへの追加
GeoCodingViewController *next = [[[GeoCodingViewController alloc] initWithKeyword:_textField.text] autorelease];
[self.navigationController pushViewController:next animated:YES];
return YES;
}
----- 以下略 -----
ここまでで、Yahoo!ジオコーダAPIを使った住所検索の一覧表示までが出来上がりました(※画像は「東京都新宿区舟町5」で検索した結果)。

