SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

スマホアプリ開発の最新トレンド! ぜったい外せない位置情報活用術

YOLPで挑戦~目的地を地図で表示するiOSアプリを、 地図ライブラリを使わずにお手軽に作る!

スマホアプリ開発の最新トレンド! ぜったい外せない位置情報活用術(5)

Yahoo!ジオコーダAPIについて

 キーワード入力画面ができたら、次はキーワードをもとにYahoo!ジオコーダAPIにアクセスして、結果一覧を表示する画面を作ります。

 が、その前にYahoo!ジオコーダAPIについて簡単に説明しようと思います。

 Yahoo!ジオコーダAPIは、キーワードとして住所を渡すと、該当する住所の候補に、緯度経度を付与した形で返すことができます。

 アクセスする一例としては、以下のようなURLです。

Yahoo!ジオコーダAPIのアクセス例
(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に書き換えてアクセスをすると、以下のようなレスポンスが返ってくるはずです。

Yahoo!ジオコーダAPIのレスポンス例
<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の形でもレスポンスを返すことができます。

住所候補リストアップ画面の作成

 さていよいよ画面を作ります。大まかな流れは以下のとおりです。

  1. 初期化の際にキーワードを取得する
  2. 基本的な画面生成を行う
  3. 画面生成後、キーワードをもとにYahoo!ジオコーダAPIにアクセスする(JSONでレスポンスを返すように指定する)
  4. 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でファイルを作ります。

GeoCodingViewController.h
#import <UIKit/UIKit.h>
 
@interface GeoCodingViewController : UITableViewController {
  NSString *_keyword;
  NSURLConnection *_connection;
  NSMutableData *_data;
  NSArray *_resultList;
}
 
- (id)initWithKeyword:(NSString *)keyword;
 
@end
GeoCodingViewController.m
#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

 これで住所候補リストアップ画面ができます。

 次に、この画面を呼び出すために、キーワード入力画面のプログラムを少しだけ書き換えます。

RootViewController.m
#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」で検索した結果)。

次のページ
Yahoo!スタティックマップAPIについて

この記事は参考になりましたか?

スマホアプリ開発の最新トレンド! ぜったい外せない位置情報活用術連載記事一覧

もっと読む

この記事の著者

宮川 博幸(ヤフー株式会社)(ミヤカワ ヒロユキ(ヤフーカブシキガイシャ))

メディアサービスカンパニー 開発本部所属。2005年度のACM主催のプログラミングコンテストでヤフーのエンジニアと話したことがきっかけとなり、2007年にヤフーに入社。道路交通情報、地図、路線にかかわり、現在はiOS版「地図 Yahoo!ロコ」アプリの開発を主とする。好きな言葉は「全ての道はローマに...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/6711 2012/08/23 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー