現在の場所を選択して地図上に詳細を表示する

このチュートリアルでは、デバイスの現在地を取得し、可能性の高い場所を特定し、最適な場所を選択するようユーザーに促し、選択した場所の地図マーカーを表示する iOS アプリを構築する方法を説明します。

Swift または Objective-C の初級または中級の知識があり、Xcode の一般的な知識がある方に適しています。地図の作成に関する高度なガイドについては、デベロッパー ガイドをご覧ください。

このチュートリアルでは、次の地図を作成します。地図マーカーはカリフォルニア州サンフランシスコに配置されますが、デバイスまたはシミュレータの場所に合わせて移動します。

このチュートリアルでは、Places SDK for iOSMaps SDK for iOSApple Core Location フレームワークを使用します。

コードを取得する

GitHub から Google Maps iOS サンプル リポジトリのクローンを作成するか、このリポジトリをダウンロードします。

または、次のボタンをクリックしてソースコードをダウンロードします。

コードをダウンロード

MapViewController

Swift

import UIKit import GoogleMaps import GooglePlaces  class MapViewController: UIViewController {    var locationManager: CLLocationManager!   var currentLocation: CLLocation?   var mapView: GMSMapView!   var placesClient: GMSPlacesClient!   var preciseLocationZoomLevel: Float = 15.0   var approximateLocationZoomLevel: Float = 10.0    // An array to hold the list of likely places.   var likelyPlaces: [GMSPlace] = []    // The currently selected place.   var selectedPlace: GMSPlace?    // Update the map once the user has made their selection.   @IBAction func unwindToMain(segue: UIStoryboardSegue) {     // Clear the map.     mapView.clear()      // Add a marker to the map.     if let place = selectedPlace {       let marker = GMSMarker(position: place.coordinate)       marker.title = selectedPlace?.name       marker.snippet = selectedPlace?.formattedAddress       marker.map = mapView     }      listLikelyPlaces()   }    override func viewDidLoad() {     super.viewDidLoad()      // Initialize the location manager.     locationManager = CLLocationManager()     locationManager.desiredAccuracy = kCLLocationAccuracyBest     locationManager.requestWhenInUseAuthorization()     locationManager.distanceFilter = 50     locationManager.startUpdatingLocation()     locationManager.delegate = self      placesClient = GMSPlacesClient.shared()      // A default location to use when location permission is not granted.     let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)      // Create a map.     let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel     let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,                                           longitude: defaultLocation.coordinate.longitude,                                           zoom: zoomLevel)     mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)     mapView.settings.myLocationButton = true     mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]     mapView.isMyLocationEnabled = true      // Add the map to the view, hide it until we've got a location update.     view.addSubview(mapView)     mapView.isHidden = true      listLikelyPlaces()   }    // Populate the array with the list of likely places.   func listLikelyPlaces() {     // Clean up from previous sessions.     likelyPlaces.removeAll()      let placeFields: GMSPlaceField = [.name, .coordinate]     placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in       guard error == nil else {         // TODO: Handle the error.         print("Current Place error: \(error!.localizedDescription)")         return       }        guard let placeLikelihoods = placeLikelihoods else {         print("No places found.")         return       }        // Get likely places and add to the list.       for likelihood in placeLikelihoods {         let place = likelihood.place         self.likelyPlaces.append(place)       }     }   }    // Prepare the segue.   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {     if segue.identifier == "segueToSelect" {       if let nextViewController = segue.destination as? PlacesViewController {         nextViewController.likelyPlaces = likelyPlaces       }     }   } }  // Delegates to handle events for the location manager. extension MapViewController: CLLocationManagerDelegate {    // Handle incoming location events.   func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {     let location: CLLocation = locations.last!     print("Location: \(location)")      let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel     let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,                                           longitude: location.coordinate.longitude,                                           zoom: zoomLevel)      if mapView.isHidden {       mapView.isHidden = false       mapView.camera = camera     } else {       mapView.animate(to: camera)     }      listLikelyPlaces()   }    // Handle authorization for the location manager.   func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {     // Check accuracy authorization     let accuracy = manager.accuracyAuthorization     switch accuracy {     case .fullAccuracy:         print("Location accuracy is precise.")     case .reducedAccuracy:         print("Location accuracy is not precise.")     @unknown default:       fatalError()     }      // Handle authorization status     switch status {     case .restricted:       print("Location access was restricted.")     case .denied:       print("User denied access to location.")       // Display the map using the default location.       mapView.isHidden = false     case .notDetermined:       print("Location status not determined.")     case .authorizedAlways: fallthrough     case .authorizedWhenInUse:       print("Location status is OK.")     @unknown default:       fatalError()     }   }    // Handle location manager errors.   func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {     locationManager.stopUpdatingLocation()     print("Error: \(error)")   } }       

Objective-C

#import "MapViewController.h" #import "PlacesViewController.h" @import CoreLocation; @import GooglePlaces; @import GoogleMaps;  @interface MapViewController () <CLLocationManagerDelegate>  @end  @implementation MapViewController {   CLLocationManager *locationManager;   CLLocation * _Nullable currentLocation;   GMSMapView *mapView;   GMSPlacesClient *placesClient;   float preciseLocationZoomLevel;   float approximateLocationZoomLevel;    // An array to hold the list of likely places.   NSMutableArray<GMSPlace *> *likelyPlaces;    // The currently selected place.   GMSPlace * _Nullable selectedPlace; }  - (void)viewDidLoad {   [super viewDidLoad];   preciseLocationZoomLevel = 15.0;   approximateLocationZoomLevel = 15.0;    // Initialize the location manager.   locationManager = [[CLLocationManager alloc] init];   locationManager.desiredAccuracy = kCLLocationAccuracyBest;   [locationManager requestWhenInUseAuthorization];   locationManager.distanceFilter = 50;   [locationManager startUpdatingLocation];   locationManager.delegate = self;    placesClient = [GMSPlacesClient sharedClient];    // A default location to use when location permission is not granted.   CLLocationCoordinate2D defaultLocation = CLLocationCoordinate2DMake(-33.869405, 151.199);    // Create a map.   float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;   GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:defaultLocation.latitude                                                           longitude:defaultLocation.longitude                                                                zoom:zoomLevel];   mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera];   mapView.settings.myLocationButton = YES;   mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;   mapView.myLocationEnabled = YES;    // Add the map to the view, hide it until we've got a location update.   [self.view addSubview:mapView];   mapView.hidden = YES;    [self listLikelyPlaces]; }  // Populate the array with the list of likely places. - (void) listLikelyPlaces {   // Clean up from previous sessions.   likelyPlaces = [NSMutableArray array];    GMSPlaceField placeFields = GMSPlaceFieldName | GMSPlaceFieldCoordinate;   [placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:placeFields callback:^(NSArray<GMSPlaceLikelihood *> * _Nullable likelihoods, NSError * _Nullable error) {     if (error != nil) {       // TODO: Handle the error.       NSLog(@"Current Place error: %@", error.localizedDescription);       return;     }      if (likelihoods == nil) {       NSLog(@"No places found.");       return;     }      for (GMSPlaceLikelihood *likelihood in likelihoods) {       GMSPlace *place = likelihood.place;       [likelyPlaces addObject:place];     }   }]; }  // Update the map once the user has made their selection. - (void) unwindToMain:(UIStoryboardSegue *)segue {   // Clear the map.   [mapView clear];    // Add a marker to the map.   if (selectedPlace != nil) {     GMSMarker *marker = [GMSMarker markerWithPosition:selectedPlace.coordinate];     marker.title = selectedPlace.name;     marker.snippet = selectedPlace.formattedAddress;     marker.map = mapView;   }    [self listLikelyPlaces]; }  // Prepare the segue. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {   if ([segue.identifier isEqualToString:@"segueToSelect"]) {     if ([segue.destinationViewController isKindOfClass:[PlacesViewController class]]) {       PlacesViewController *placesViewController = (PlacesViewController *)segue.destinationViewController;       placesViewController.likelyPlaces = likelyPlaces;     }   } }  // Delegates to handle events for the location manager. #pragma mark - CLLocationManagerDelegate  // Handle incoming location events. - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {   CLLocation *location = locations.lastObject;   NSLog(@"Location: %@", location);    float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;   GMSCameraPosition * camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude                                                            longitude:location.coordinate.longitude                                                                 zoom:zoomLevel];    if (mapView.isHidden) {     mapView.hidden = NO;     mapView.camera = camera;   } else {     [mapView animateToCameraPosition:camera];   }    [self listLikelyPlaces]; }  // Handle authorization for the location manager. - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {   // Check accuracy authorization   CLAccuracyAuthorization accuracy = manager.accuracyAuthorization;   switch (accuracy) {     case CLAccuracyAuthorizationFullAccuracy:       NSLog(@"Location accuracy is precise.");       break;     case CLAccuracyAuthorizationReducedAccuracy:       NSLog(@"Location accuracy is not precise.");       break;   }    // Handle authorization status   switch (status) {     case kCLAuthorizationStatusRestricted:       NSLog(@"Location access was restricted.");       break;     case kCLAuthorizationStatusDenied:       NSLog(@"User denied access to location.");       // Display the map using the default location.       mapView.hidden = NO;     case kCLAuthorizationStatusNotDetermined:       NSLog(@"Location status not determined.");     case kCLAuthorizationStatusAuthorizedAlways:     case kCLAuthorizationStatusAuthorizedWhenInUse:       NSLog(@"Location status is OK.");   } }  // Handle location manager errors. - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {   [manager stopUpdatingLocation];   NSLog(@"Error: %@", error.localizedDescription); }  @end       

PlacesViewController

Swift

import UIKit import GooglePlaces  class PlacesViewController: UIViewController {    // ...    // Pass the selected place to the new view controller.   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {     if segue.identifier == "unwindToMain" {       if let nextViewController = segue.destination as? MapViewController {         nextViewController.selectedPlace = selectedPlace       }     }   } }  // Respond when a user selects a place. extension PlacesViewController: UITableViewDelegate {   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {     selectedPlace = likelyPlaces[indexPath.row]     performSegue(withIdentifier: "unwindToMain", sender: self)   }    // Adjust cell height to only show the first five items in the table   // (scrolling is disabled in IB).   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {     return self.tableView.frame.size.height/5   }    // Make table rows display at proper height if there are less than 5 items.   func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {     if (section == tableView.numberOfSections - 1) {       return 1     }     return 0   } }  // Populate the table with the list of most likely places. extension PlacesViewController: UITableViewDataSource {   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {     return likelyPlaces.count   }    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {     let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)     let collectionItem = likelyPlaces[indexPath.row]      cell.textLabel?.text = collectionItem.name      return cell   } }       

Objective-C

#import "PlacesViewController.h"  @interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate> // ...  -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {  }  #pragma mark - UITableViewDelegate  // Respond when a user selects a place. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {   self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row];   [self performSegueWithIdentifier:@"unwindToMain" sender:self]; }  // Adjust cell height to only show the first five items in the table // (scrolling is disabled in IB). -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {   return self.tableView.frame.size.height/5; }  // Make table rows display at proper height if there are less than 5 items. -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {   if (section == tableView.numberOfSections - 1) {     return 1;   }   return 0; }  #pragma mark - UITableViewDataSource  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {   return self.likelyPlaces.count; }  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {   return [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier forIndexPath:indexPath]; } @end       

始める

Swift Package Manager

Maps SDK for iOS は、Swift Package Manager を使用してインストールできます。

  1. 既存の Maps SDK for iOS の依存関係を削除します。
  2. ターミナル ウィンドウを開いて、tutorials/current-place-on-map ディレクトリに移動します。
  3. Xcode ワークスペースを閉じて、次のコマンドを実行します。
            sudo gem install cocoapods-deintegrate cocoapods-clean         pod deintegrate         pod cache clean --all         rm Podfile         rm current-place-on-map.xcworkspace
  4. Xcode プロジェクトを開き、podfile を削除します。
  5. Places SDK と Maps SDK を追加します。
    1. [File] > [Add Package Dependencies] に移動します。
    2. URL として https://github.com/googlemaps/ios-places-sdk を入力し、Enter キーを押してパッケージをプルし、[パッケージを追加] をクリックします。
    3. URL として https://github.com/googlemaps/ios-maps-sdk を入力し、Enter キーを押してパッケージをプルし、[パッケージを追加] をクリックします。
  6. [File] > [Packages] > [Reset Package Cache] を使用して、パッケージ キャッシュをリセットする必要がある場合があります。

CocoaPods を使用

  1. Xcode バージョン 16.0 以降をダウンロードしてインストールします。
  2. CocoaPods がまだインストールされていない場合は、ターミナルから次のコマンドを実行して、macOS にインストールします。
    sudo gem install cocoapods
  3. tutorials/current-place-on-map ディレクトリに移動します。
  4. pod install コマンドを実行します。Podfile で指定した Maps SDK と Places SDK とその依存関係がインストールされます。
  5. pod outdated を実行して、インストールされている Pod のバージョンと新しい更新を比較します。新しいバージョンが検出された場合は、pod update を実行して Podfile を更新し、最新の SDK をインストールします。詳しくは、CocoaPods ガイドをご覧ください。
  6. プロジェクトの current-place-on-map.xcworkspace ファイルを(ダブルクリックして)開き、Xcode で開きます。このプロジェクトを開くには .xcworkspace ファイルを使用する必要があります。

API キーを取得して必要な API を有効にする

このチュートリアルを完了するには、Maps SDK for iOSPlaces API の使用が許可されている Google API キーが必要です。

  1. Google Maps Platform スタートガイドの手順に沿って、これらの両方のプロダクトが有効になっている請求先アカウントとプロジェクトを設定します。
  2. API キーを取得するの手順に沿って、以前に設定した開発プロジェクトの API キーを作成します。

API キーをアプリに追加する

次のように、API キーを AppDelegate.swift に追加します。

  1. 以下のインポート文がファイルに追加済みであることを確認します。
    import GooglePlaces import GoogleMaps
  2. application(_:didFinishLaunchingWithOptions:) メソッドで次の行を編集し、「YOUR_API_KEY」YOUR_API_KEYをお客様の API キーに置き換えます。
    GMSPlacesClient.provideAPIKey("YOUR_API_KEY") GMSServices.provideAPIKey("YOUR_API_KEY")

アプリをビルドして実行する

  1. iOS デバイスをパソコンに接続するか、Xcode スキーム メニューからシミュレータを選択します。
  2. デバイスを使用している場合は、位置情報サービスが有効になっていることを確認してください。シミュレータを使用している場合は、[機能] メニューから場所を選択します。
  3. Xcode で、[Product/Run] メニュー オプション(またはプレイボタン アイコン)をクリックします。
  • Xcode がアプリをビルドし、デバイスまたはシミュレータ上で実行します。
  • 現在地の周辺に多数のマーカーが追加された地図が表示されます。

トラブルシューティング:

  • 地図が表示されない場合は、上記の手順どおりに API キーを取得してアプリに追加しているかご確認ください。Xcode のデバッグ コンソールで、API キーに関するエラー メッセージを確認します。
  • API キーに iOS バンドル ID による制限をかけている場合は、今回のアプリのバンドル ID(com.google.examples.current-place-on-map)を追加して許可してください。
  • 位置情報サービスの権限リクエストが拒否されると、地図が正しく表示されません。
    • デバイスを使用している場合は、[設定] / [一般] / [プライバシー] / [位置情報サービス] に移動して、位置情報サービスを再度有効にします。
    • シミュレータを使用している場合は、[Simulator] / [Reset Content and Settings...] に移動します。
    次回アプリを実行するときに、位置情報サービスのプロンプトを必ず受け入れてください。
  • Wi-Fi または GPS の接続状態が良好であることを確認します。
  • アプリは起動するものの地図が表示されない場合は、プロジェクトの Info.plist を適切な位置情報権限で更新していることを確認してください。権限の処理について詳しくは、以下のアプリで位置情報の利用許可をリクエストするためのガイドをご覧ください。
  • ログを表示してアプリをデバッグするには、Xcode デバッグツールを使用します。

コードを理解する

チュートリアルのこのパートでは、current-place-on-map アプリの最も重要な部分について説明します。この内容は、同様のアプリの作成方法を理解するうえで役に立ちます。

current-place-on-map アプリには 2 つのビュー コントローラがあります。1 つはユーザーが選択した場所を示す地図を表示するもので、もう 1 つはユーザーが選択できる場所の候補リストを表示するものです。各ビュー コントローラには、候補地のリストをトラッキングする変数(likelyPlaces)と、ユーザーの選択を示す変数(selectedPlace)が同じように存在します。ビュー間のナビゲーションは、セグエを使用して行われます。

位置情報の利用許可をリクエストする

アプリでは、位置情報サービスの使用に関する同意をユーザーに求める必要があります。そのためには、アプリの Info.plist ファイルに NSLocationAlwaysUsageDescription キーを含め、各キーの値を、アプリが位置情報をどのように使用するのかを説明する文字列に設定します。

位置情報マネージャーを設定する

CLLocationManager を使用して、デバイスの現在地を特定し、デバイスが新しい場所に移動したときに定期的な更新をリクエストします。このチュートリアルでは、デバイスの位置情報を取得するために必要なコードを提供します。詳しくは、Apple デベロッパー ドキュメントのユーザーの位置情報を取得するをご覧ください。

  1. クラスレベルで、位置情報マネージャー、現在地、地図ビュー、プレイス クライアント、デフォルトのズームレベルを宣言します。
  2. Swift

    var locationManager: CLLocationManager! var currentLocation: CLLocation? var mapView: GMSMapView! var placesClient: GMSPlacesClient! var preciseLocationZoomLevel: Float = 15.0 var approximateLocationZoomLevel: Float = 10.0       

    Objective-C

    CLLocationManager *locationManager; CLLocation * _Nullable currentLocation; GMSMapView *mapView; GMSPlacesClient *placesClient; float preciseLocationZoomLevel; float approximateLocationZoomLevel;       
  3. viewDidLoad() で位置情報マネージャーと GMSPlacesClient を初期化します。
  4. Swift

    // Initialize the location manager. locationManager = CLLocationManager() locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.distanceFilter = 50 locationManager.startUpdatingLocation() locationManager.delegate = self  placesClient = GMSPlacesClient.shared()       

    Objective-C

    // Initialize the location manager. locationManager = [[CLLocationManager alloc] init]; locationManager.desiredAccuracy = kCLLocationAccuracyBest; [locationManager requestWhenInUseAuthorization]; locationManager.distanceFilter = 50; [locationManager startUpdatingLocation]; locationManager.delegate = self;  placesClient = [GMSPlacesClient sharedClient];       
  5. 可能性のある場所のリストとユーザーが選択した場所を保持する変数を宣言します。
  6. Swift

    // An array to hold the list of likely places. var likelyPlaces: [GMSPlace] = []  // The currently selected place. var selectedPlace: GMSPlace?       

    Objective-C

    // An array to hold the list of likely places. NSMutableArray<GMSPlace *> *likelyPlaces;  // The currently selected place. GMSPlace * _Nullable selectedPlace;       
  7. 拡張句を使用して、位置情報マネージャーのイベントを処理するデリゲートを追加します。
  8. Swift

    // Delegates to handle events for the location manager. extension MapViewController: CLLocationManagerDelegate {    // Handle incoming location events.   func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {     let location: CLLocation = locations.last!     print("Location: \(location)")      let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel     let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,                                           longitude: location.coordinate.longitude,                                           zoom: zoomLevel)      if mapView.isHidden {       mapView.isHidden = false       mapView.camera = camera     } else {       mapView.animate(to: camera)     }      listLikelyPlaces()   }    // Handle authorization for the location manager.   func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {     // Check accuracy authorization     let accuracy = manager.accuracyAuthorization     switch accuracy {     case .fullAccuracy:         print("Location accuracy is precise.")     case .reducedAccuracy:         print("Location accuracy is not precise.")     @unknown default:       fatalError()     }      // Handle authorization status     switch status {     case .restricted:       print("Location access was restricted.")     case .denied:       print("User denied access to location.")       // Display the map using the default location.       mapView.isHidden = false     case .notDetermined:       print("Location status not determined.")     case .authorizedAlways: fallthrough     case .authorizedWhenInUse:       print("Location status is OK.")     @unknown default:       fatalError()     }   }    // Handle location manager errors.   func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {     locationManager.stopUpdatingLocation()     print("Error: \(error)")   } }       

    Objective-C

    // Delegates to handle events for the location manager. #pragma mark - CLLocationManagerDelegate  // Handle incoming location events. - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {   CLLocation *location = locations.lastObject;   NSLog(@"Location: %@", location);    float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;   GMSCameraPosition * camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude                                                            longitude:location.coordinate.longitude                                                                 zoom:zoomLevel];    if (mapView.isHidden) {     mapView.hidden = NO;     mapView.camera = camera;   } else {     [mapView animateToCameraPosition:camera];   }    [self listLikelyPlaces]; }  // Handle authorization for the location manager. - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {   // Check accuracy authorization   CLAccuracyAuthorization accuracy = manager.accuracyAuthorization;   switch (accuracy) {     case CLAccuracyAuthorizationFullAccuracy:       NSLog(@"Location accuracy is precise.");       break;     case CLAccuracyAuthorizationReducedAccuracy:       NSLog(@"Location accuracy is not precise.");       break;   }    // Handle authorization status   switch (status) {     case kCLAuthorizationStatusRestricted:       NSLog(@"Location access was restricted.");       break;     case kCLAuthorizationStatusDenied:       NSLog(@"User denied access to location.");       // Display the map using the default location.       mapView.hidden = NO;     case kCLAuthorizationStatusNotDetermined:       NSLog(@"Location status not determined.");     case kCLAuthorizationStatusAuthorizedAlways:     case kCLAuthorizationStatusAuthorizedWhenInUse:       NSLog(@"Location status is OK.");   } }  // Handle location manager errors. - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {   [manager stopUpdatingLocation];   NSLog(@"Error: %@", error.localizedDescription); }       

地図を追加する

マップを作成し、メインビュー コントローラの viewDidLoad() でビューに追加します。地図は、位置情報の更新を受信するまで非表示のままになります(位置情報の更新は CLLocationManagerDelegate 拡張機能で処理されます)。

Swift

// A default location to use when location permission is not granted. let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)  // Create a map. let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,                                       longitude: defaultLocation.coordinate.longitude,                                       zoom: zoomLevel) mapView = GMSMapView.map(withFrame: view.bounds, camera: camera) mapView.settings.myLocationButton = true mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] mapView.isMyLocationEnabled = true  // Add the map to the view, hide it until we've got a location update. view.addSubview(mapView) mapView.isHidden = true       

Objective-C

// A default location to use when location permission is not granted. CLLocationCoordinate2D defaultLocation = CLLocationCoordinate2DMake(-33.869405, 151.199);  // Create a map. float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel; GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:defaultLocation.latitude                                                         longitude:defaultLocation.longitude                                                              zoom:zoomLevel]; mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera]; mapView.settings.myLocationButton = YES; mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; mapView.myLocationEnabled = YES;  // Add the map to the view, hide it until we've got a location update. [self.view addSubview:mapView]; mapView.hidden = YES;       

現在地の選択をユーザーに求める

Places SDK for iOS を使用して、ユーザーの現在地に基づいて上位 5 つの場所の可能性を取得し、UITableView でリストを表示します。ユーザーが場所を選択したら、地図にマーカーを追加します。

  1. UITableView に入力する可能性の高い場所のリストを取得します。ユーザーは、このリストから現在地を選択できます。
  2. Swift

    // Populate the array with the list of likely places. func listLikelyPlaces() {   // Clean up from previous sessions.   likelyPlaces.removeAll()    let placeFields: GMSPlaceField = [.name, .coordinate]   placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in     guard error == nil else {       // TODO: Handle the error.       print("Current Place error: \(error!.localizedDescription)")       return     }      guard let placeLikelihoods = placeLikelihoods else {       print("No places found.")       return     }      // Get likely places and add to the list.     for likelihood in placeLikelihoods {       let place = likelihood.place       self.likelyPlaces.append(place)     }   } }       

    Objective-C

    // Populate the array with the list of likely places. - (void) listLikelyPlaces {   // Clean up from previous sessions.   likelyPlaces = [NSMutableArray array];    GMSPlaceField placeFields = GMSPlaceFieldName | GMSPlaceFieldCoordinate;   [placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:placeFields callback:^(NSArray<GMSPlaceLikelihood *> * _Nullable likelihoods, NSError * _Nullable error) {     if (error != nil) {       // TODO: Handle the error.       NSLog(@"Current Place error: %@", error.localizedDescription);       return;     }      if (likelihoods == nil) {       NSLog(@"No places found.");       return;     }      for (GMSPlaceLikelihood *likelihood in likelihoods) {       GMSPlace *place = likelihood.place;       [likelyPlaces addObject:place];     }   }]; }       
  3. 新しいビューを開き、ユーザーの現在地である可能性の高い場所を表示します。ユーザーが [Get Place] をタップすると、新しいビューに切り替わり、選択可能な場所のリストが表示されます。prepare 関数は、現在地候補のリストで PlacesViewController を更新します。セグエが実行されると、この関数は自動的に呼び出されます。
  4. Swift

    // Prepare the segue. override func prepare(for segue: UIStoryboardSegue, sender: Any?) {   if segue.identifier == "segueToSelect" {     if let nextViewController = segue.destination as? PlacesViewController {       nextViewController.likelyPlaces = likelyPlaces     }   } }       

    Objective-C

    // Prepare the segue. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {   if ([segue.identifier isEqualToString:@"segueToSelect"]) {     if ([segue.destinationViewController isKindOfClass:[PlacesViewController class]]) {       PlacesViewController *placesViewController = (PlacesViewController *)segue.destinationViewController;       placesViewController.likelyPlaces = likelyPlaces;     }   } }       
  5. PlacesViewController で、UITableViewDataSource デリゲート拡張機能を使用して、最も可能性の高い場所のリストを使用してテーブルを入力します。
  6. Swift

    // Populate the table with the list of most likely places. extension PlacesViewController: UITableViewDataSource {   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {     return likelyPlaces.count   }    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {     let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)     let collectionItem = likelyPlaces[indexPath.row]      cell.textLabel?.text = collectionItem.name      return cell   } }       

    Objective-C

    #pragma mark - UITableViewDataSource  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {   return self.likelyPlaces.count; }  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {   return [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier forIndexPath:indexPath]; } @end       
  7. UITableViewDelegate デリゲート拡張機能を使用して、ユーザーの選択を処理します。
  8. Swift

    class PlacesViewController: UIViewController {    // ...    // Pass the selected place to the new view controller.   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {     if segue.identifier == "unwindToMain" {       if let nextViewController = segue.destination as? MapViewController {         nextViewController.selectedPlace = selectedPlace       }     }   } }  // Respond when a user selects a place. extension PlacesViewController: UITableViewDelegate {   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {     selectedPlace = likelyPlaces[indexPath.row]     performSegue(withIdentifier: "unwindToMain", sender: self)   }    // Adjust cell height to only show the first five items in the table   // (scrolling is disabled in IB).   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {     return self.tableView.frame.size.height/5   }    // Make table rows display at proper height if there are less than 5 items.   func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {     if (section == tableView.numberOfSections - 1) {       return 1     }     return 0   } }       

    Objective-C

    @interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate> // ...  -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {  }  #pragma mark - UITableViewDelegate  // Respond when a user selects a place. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {   self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row];   [self performSegueWithIdentifier:@"unwindToMain" sender:self]; }  // Adjust cell height to only show the first five items in the table // (scrolling is disabled in IB). -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {   return self.tableView.frame.size.height/5; }  // Make table rows display at proper height if there are less than 5 items. -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {   if (section == tableView.numberOfSections - 1) {     return 1;   }   return 0; }       

地図にマーカーを追加する

ユーザーが選択したら、アンワインド セグエを使用して前のビューに戻り、マーカーを地図に追加します。unwindToMain IBAction は、メインビュー コントローラに戻ると自動的に呼び出されます。

Swift

// Update the map once the user has made their selection. @IBAction func unwindToMain(segue: UIStoryboardSegue) {   // Clear the map.   mapView.clear()    // Add a marker to the map.   if let place = selectedPlace {     let marker = GMSMarker(position: place.coordinate)     marker.title = selectedPlace?.name     marker.snippet = selectedPlace?.formattedAddress     marker.map = mapView   }    listLikelyPlaces() }       

Objective-C

// Update the map once the user has made their selection. - (void) unwindToMain:(UIStoryboardSegue *)segue {   // Clear the map.   [mapView clear];    // Add a marker to the map.   if (selectedPlace != nil) {     GMSMarker *marker = [GMSMarker markerWithPosition:selectedPlace.coordinate];     marker.title = selectedPlace.name;     marker.snippet = selectedPlace.formattedAddress;     marker.map = mapView;   }    [self listLikelyPlaces]; }       

これで完了です。ユーザーが現在地を選択して、その結果を Google マップに表示する iOS アプリを作成しました。この過程で、Places SDK for iOSMaps SDK for iOSApple Core Location フレームワークの使用方法を学習しました。