[iOSアプリ開発] お天気アプリ:API

iPhoneで動く「お天気アプリ」を作成してみませんか?

都市名や現在地情報を利用して、天気情報を取得し(APIを使用)、スマートフォン画面に都市名、温度、天気イメージを表示するお天気アプリを作成します。

目次

概要

この講座で学習する内容
  • お天気アプリを作成

アプリを作成する過程で、以下の内容を学習できます。

  • プロトコルを使用したデリゲートデザインパターン
  • クロージャー
  • JSONデータのパースについて
  • UITextFieldの使い方
  • ダークモード対応の色設定
  • 内部パラメータ、外部パラメータ
  • Extension

MVCデザインパターンを適用しています。
Model(M)、View(V)、Controller(C
記事中、M、V、Cの略を使用しています。

参考にした講座】iOS & Swift – The Complete iOS App Development Bootcamp (Udemy)
 (Section13) Networking, JSON Parsing, APIs and Core Location

この講座で作成するアプリの概要

都市名の入力、あるいは現在地取得ボタン(左上ボタン)から入手する経度、緯度の情報から天気情報を入手し、UIに「天気イメージ図」、「温度」、「都市名」を表示するアプリです。

アプリ内のデータの流れは以下の通りです。

  1. 都市名をUITextFieldに入力します。
    現在地取得ボタン(左上ボタン)から経度、緯度の情報を入手します。
  2. 天気情報を入手するためのURLを作成します。
  3. URLの宛先「Open Weather(https://openweathermap.org)」から天気情報を取得します。
  4. 入手した天気情報(JSONデータ)をパースし、アプリ内に「天気イメージ図の基礎となるデータ」、「温度」、「都市名」を取り込みます。
  5. 「天気イメージ図の基礎となるデータ」は、switch文を使用して対応表を作成し、天気イメージ図に変換します
  6. 天気データが更新されると、デリゲートデザインパターンが発動し、天気情報をUIに送信します
  7. UIに「天気イメージ図」、「温度」、「都市名」が表示されます。
アプリの開発環境(2023年5月5日現在)
  • Xcode: Version 14.3
  • macOS: Venture: Version 13.3.1
  • iOS: 16.4.1
Xcodeのインストールが未了の方はこちら
GitHubからプロジェクトを入手したい方はこちら

UIの設定

開始プロジェクトをクローンして起動した状態を確認してみましょう。

開始プロジェクトの確認

開始プロジェクトの確認
  1. 階層図より、
    Modelフォルダ(M):ファイルなし
    Viewフォルダ(V):Main.storyboardファイル
    Controllerフォルダ(C):WeatherViewControllerファイル
    があることがわかります。
  2. Mainには、上からTextField(検索用)、天気図イメージView(SF Symbols)、温度ラベル、都市名ラベルがあります。
  3. 天気イメージView、温度ラベル、都市名ラベルは、すでにWeatherViewControllerとリンクされています。

ダークモードに対応した色の設定

現在使用しているデバイスのダークモードについては、Macの場合はシステム設定、Xcodeの場合はSettingsから変更できます。

ダークモード、ライトモードのデバイス設定
Mac
「システム設定」→「外観」から設定できる。選択肢は、「ライト」「ダーク」「自動」の3つ。
Xcode
「Settings」→「General」→「Appearance」から設定できる。選択肢は、「システム」「ライト」「ダーク」の3つ。「システム」を選択した場合は、Macで設定した内容が引き継がれる。

Xcode上で動くデバイスのダークモード、ライトモードに対応した色の設定を行う。

Xcodeで動くデバイスの色の切り替えについて
ライトモード
ダークモード
  • 下の小さい四角枠をクリックすると、Xcode上で動くデバイスのライトモード、ダークモードの切り替えができる。
  • 赤枠で囲んだ、文字、SF Symbolなどについては、システムカラーが設定されているため、自動で黒(ライトモード)→白(ダークモード)の切り替えがされる。

しかし、カスタムカラーを選択した場合は、自動で色の切り替えがされないため、個別で設定する必要があります
その方法について、解説します。

STEP
カスタムカラーの設定
カスタムカラーの設定(ライトモード)
Sunの画像(SF Symbol)の色をカスタムカラーに変更しました。
カスタムカラーの色は森の深緑色をスポイトを使って設定しました。
カスタムカラーの設定(ダークモード)

ダークモードに切り替えましたが、Sunの画像(SF Symbol)の色は、変わらない(深緑色のまま)ことがわかります。

STEP
カラーセットの追加
カラーセットの追加-1
「Assets.xcassets」→「+ボタン」→「Color Set」の順に選択します
カラーセットの追加-2
「Appearance」から「Any, Light, Darl」を選択すると、箱が3つ用意される
STEP
色の登録
カラーパレットの登録

先程、Sunの画像(SF Symbol)に選択した、深緑色をカラーパレットに登録しておきます。

ドラッグすれば登録できる
カラーセットに色の登録
  • 「ShowColorPanel」を選択し、カラーパレットを出します
  • カラーパレットから深緑色を選択します
  • 「AnyAppearance」「Light」に深緑色を選択、「Dark」はデフォルトの白色にしておきます
  • 右上のNameに「weatherColor」と登録し、後から呼び出せるようにしておきます。
STEP
Sunの画像(SF Symbol)を登録したカラーセットに変更する
  • Sunの画像の色を「weatherColor」に変更します。
  • ライトモードからダークモードに変更すると、Sunの画像の色が深緑色から白色(weatherColorで登録した内容)に変わることが確認できます。
ライトモード
ダークモード

ベクター画像の登録

背景画像をスカラー画像から、ベクター画像に変更します。

スカラー画像、ベクター画像
  • スカラー画像(PNG, JPEGなど)
    拡大すると、画像がピクセル化するため、画質が荒くなり、拡大した画像を綺麗に見ることができない。
  • ベクター画像(PDFなど)
    拡大してもピクセル化しないため、常にシャープな画質を保つことができる。
STEP
「Assets.xcassets」にベクター画像を登録する
「Resizing」の「Preserve Vector Data」にチェックマーク
「Scales」hは「Single Scale」を選択します
STEP
ダークモード、ライトモード用の背景画像を登録する
「Appearance」は「Any, Light, Dark」を選択します
「Any, Light」には、ライトモード用の画像、
「Dark」には、ダークモード用の画像を登録します。
最後に、名前を最初と同じ「background」に変更します。
STEP
背景画像の確認

背景画像が、ライトモード用→ダークモード用に切り替わることが確認できます。

ライトモード
ダークモード

UITextFieldを設定する

テキストフィールドは、ユーザがiPhoneのキーボードを使って入力できるようにするための場所です。

UITextFieldの主な入力規則
  1. Capitalization(大文字にする)
    単語の先頭、文章の先頭、全て
  2. Keyboard Type(キーボードタイプの変更)
    数字パッド、メールアドレス、Twitter用など
  3. Return Key(リターンキー)
    Go、Google、Search、Sendなど
  4. Secure Text Entry(暗証番号入力)
    入力値が非表示(マル)になる
STEP
リンクを作成
UITextFieldのリンクを作成
STEP
入力規則の設定
UITextFieldの設定
Placefolder は「都市名を入力」、Capitalizationは「Word」、Return Keyは「Go」を選択します
STEP
Goボタンを押して、入力した値をコンソール出力する

テキストフィールドに入力後、右上の検索ボタンをクリックすると、IBActionが起動して、入力した値をコンソール出力できます。

キーボードに設定した「Go」ボタンを押しても、同様に、入力した値をコンソール出力できるようにコードを追加します。

Goボタンを押して、入力した値をコンソール出力する
  • UITextFieldDelegateを自身(self)に設定する
  • UITextFieldに何か起きると連絡が来るようになる
  • textFieldShouldReturnは、Returnキー(Goボタン)が押された時に発動する
  • 今回は、「Tokyo」と入力し、Goボタンを押すと、「Tokyo」がコンソール出力されました。
STEP
入力後、キーボードを閉じる

次に、入力が完了したら、キーボードを閉じるコードを追加します。

入力後、キーボードを閉じる:textFieldShouldReturn
//検索ボタン 押した時
@IBAction func searchPressed(_ sender: UIButton) {
//キーボードを閉じるコード
    searchTextField.endEditing(true)  
    print(searchTextField.text!)
}

//キーボード  Enterキーが押された時 
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
//キーボードを閉じるコード
    searchTextField.endEditing(true)  
    print(searchTextField.text!)
    return true
}
STEP
入力が完了し、検索ボタン(Goボタン)を押すと入力値が消えるようにする
検索ボタン(Goボタン)後、入力値を消す:textFieldDidEndEditing
//入力が終わった時
func textFieldDidEndEditing(_ textField: UITextField) {
    searchTextField.text = ""
}
STEP
未入力の時、PlaceHolderで警告する
未入力の時、PlaceHolderで警告:textFieldShouldEndEditing
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    if textField.text != "" {
        return true
    } else {
        textField.placeholder = "何か入力して下さい" //警告文に変更
        return false
    }
}

都市名から天気データを取得する

SafariからAPIを使用して現在の天気データを取得

APIとは、「Application Programming Interface」の略で、ソフトウエアを作るため、あるいは外部システムとやりとりするために使用されます。

天気データは、「Open Weather(https://openweathermap.org)」から取得します。

今回作成するアプリは、都市名を入力して天気データを入手するため、以下の条件を指定してインターネットから情報を取得してみます。

API keyは、ログイン後、取得する必要があります。
https://openweathermap.org/current#cityid

都市名に「東京」を入れて、インターネットから天気データを取得してみました。

https://api.openweathermap.org/data/2.5
  • データを見やすくするため、Safariの拡張機能の「PrettyJSON」を利用して出力しています
  • 東京の気温が293.12Kであることがわかります

温度が絶対温度(ケルビン)になっているため、摂氏(℃)表示に変更します

API callの条件に「&units=metric」を追記して、再度データを取得してみました。

https://api.openweathermap.org/data/2.5

アプリからAPIを使用して天気データを取得

今度は、天気データをアプリ上でプログラムコードから取得してみます。

STEP
天気データ取得用URLの作成

新たにModelファイル(WeathrManager)を作成します。

WeatherViewController(C)
class WeatherViewController: UIViewController, 
    UITextFieldDelegate {
    var weatherManager = WeathrManager()

    func textFieldDidEndEditing(_ textField: UITextField) {
        
        if let city = searchTextField.text {
            weatherManager.fetchWeather(cityName: city)
        }
        searchTextField.text = ""
    }
}

テキストフィールドから入手したcityNameデータを、WeathrManager(M)に渡しています。

WeatherManager(M)
import Foundation

struct WeathrManager {
    let weatherURL =
        "https://api.openweathermap.org/data/2.5
        /weather?appid=???&units=metric"
        //???にはAPIキーの数値を入力

    func fetchWeather(cityName: String) {
        let urlString = "\(weatherURL)&q=\(cityName)"
        print(urlString)
    }
}

都市名については、WeatherViewController(C)からcityNameデータを取得し、URLに追記しています。

STEP
作成したURLを送信し、天気データを入手する

天気データは以下の順序で入手します。実際のコードも記載しますので確認ください。

  • URL作成
  • URLセッション作成
  • セッションにタスクを付与
  • タスクの開始

入手したタスクデータは、エンコード(.utf8)して出力しました。

WeatherManager(M):handle関数
クロージャー化する前
struct WeathrManager {
    let weatherURL =
        "https://api.openweathermap.org/data/2.5
        /weather?appid=???&units=metric"
        //???にはAPIキーの数値を入力

    func fetchWeather(cityName: String) {
        let urlString = "\(weatherURL)&q=\(cityName)"
        performRequest(urlString: urlString)
    }
    
    func performRequest(urlString: String) {

        //1. URL作成
        if let url = URL(string: urlString) {

            //2. URLセッション作成
            let session = URLSession(configuration: .default)
            
            //3. セッションにタスクを付与
            let task = session.dataTask(with: url, 
            completionHandler: handle(data:response:error:))
            
            //4. タスクの開始
            task.resume()
        }
    }
    
    func handle(data: Data?, 
        response: URLResponse?, error: Error?) {

        if error != nil {
            print(error!)
            return
        }
        
        if let safeData = data {
            let dataString = String(data: safeData, 
                encoding: .utf8)

            print(dataString)
        }
    }
}

handle関数をクロージャーに変換

WeathrManager(M)の中にあるhandle関数について、クロージャーに変換しました。

WeatherManager(M):handle関数
クロージャー化した後
import Foundation

struct WeathrManager {
    let weatherURL =
        "https://api.openweathermap.org/data/2.5
        /weather?appid=???&units=metric"
    
    func fetchWeather(cityName: String) {
        let urlString = "\(weatherURL)&q=\(cityName)"
        performRequest(urlString: urlString)
    }
    
    func performRequest(urlString: String) {

        //1. URL作成
        if let url = URL(string: urlString) {

            //2. URLセッション作成
            let session = URLSession(configuration: .default)
            
            //3. セッションにタスクを付与
//クロージャー化
            let task = session.dataTask(with: url) { 
                (data, response, error) in

                if error != nil {
                    print(error!)
                    return
                }
                
                if let safeData = data {
                    let dataString = String(data: safeData, 
                        encoding: .utf8)

                    print(dataString)
                }
            }
            
            //4. タスクの開始
            task.resume()
        }
    }
}

JSONデータのパース

APIを使用して天気データをアプリ上で取得することができるようになりましたが、必要なデータだけ抽出するようにしましょう。

そこで、JSON形式のデータをデコーディングし、都市名(name)、温度(temp)、天気イメージ(description)のデータのみ出力することにします。

STEP
データ格納するモデルファイルWeatherData(M)作成

データが格納されている階層に従い、WeatherData(M)ファイルのデータ階層を作成する。

WeatherData(M)
import Foundation

struct WeatherData: Decodable {
    let name: String
    let main: Main
    let weather: [Weather]
}

struct Main: Decodable {
    let temp: Double
}

struct Weather: Decodable {
    let description: String
}
STEP
WeatherData(M)でデコードしたデータの出力

入手した天気データをデコード化し、
都市名(name)、温度(temp)、天気イメージ(description)のみ
WeatherData構造体に格納する。

WeatherManager(M)

天気データから天気イメージを変更する

天気データIDから天気イメージを変更できるように、コードを追記します

天気データID
天気イメージ
WeatherManager(M-1)
func parseJSON(weatherData: Data) {
    let decoder = JSONDecoder()
    do {
        let decodedData = 
            try decoder.decode(WeatherData.self, 
                from: weatherData)
        let id = decodedData.weather[0].id
        let name = decodedData.name
        let temp = decodedData.main.temp
            
        let weather = 
            WeatherModel(conditionID: id, 
                         cityName: name, 
                         temperature: temp)
    } catch {
        print(error)
    }
}
WeatherModel(M-2)
struct WeatherModel {
    let conditionId: Int
    let cityName: String
    let temperature: Double

//計算プロパティ
    var conditionName: String {
        switch conditionID {
            case 200...232:
                return "cloud.bolt"
            case 300...321:
                return "cloud.drizzle"
            case 500...531:
                return "cloud.rain"
            case 600...622:
                return "cloud.snow"
            case 701...781:
                return "cloud.fog"
            case 800:
                return "sun.max"
            case 801...804:
                return "cloud.bolt"
            default:
                return "cloud"
        }
    }
}
WeatherData(M-3)
struct Weather: Decodable {
    let description: String
    let id: Int
}

データの流れ

  • WeatherData(M-3):struct Weatherの中に
    let id: Intを追記
  • WeatherModel(M-2)を新設conditionIDに対応する天気イメージの名前(conditionName)に変換
  • WeathrManager(M-1):
    ①WeatherData(M-3)からidを入手
    ②入手したidをWeatherModel(M-2)に送付

都市名から取得した天気データをUIに表示する

更新された天気データをViewに渡す方法

WeatherManager(M-1)において、APIを使用して天気データが更新されると、
WeatherViewController(C)が、更新された天気データを入手する仕組み

デリゲートデザインパターン

を実装するコードを追記します。

WeatherManager(M-1)
//プロトコルの定義
protocol WeatherManagerDelegate {  
    func didUpdateWeather(_ weatherManager: WeatherManager, 
        weather: WeatherModel)
}

struct WeatherManager {

//「WeatherManagerDelegate」の司令塔
    var delegate: WeatherManagerDelegate?
    func performRequest(urlString: String) {

    if let safeData = data {
        if let weather = 
         self.parseJSON(weatherData: safeData) {

//天気データが更新されると、didUpdateWeatherが発動し、更新データを送付
            self.delegate?.didUpdateWeather(self, 
             weather: weather)
        }
    }
}
  • //「WeatherManagerDelegate」プロトコルの定義
  • //「WeatherManagerDelegate」の司令塔
  • //天気データが更新されると、didUpdateWeatherが発動し、更新データを送付
WeatherViewController(C)
//「WeatherManagerDelegate」の実装
class WeatherViewController: UIViewController, 
    WeatherManagerDelegate {
    var weatherManager = WeatherManager()

    override func viewDidLoad() {
        super.viewDidLoad()

// 「WeatherManagerDelegate」の受信者      
        weatherManager.delegate = self
    }

//天気データが更新されると、didUpdateWeatherが発動し、更新データを受信
    func didUpdateWeather(_ weatherManager: WeatherManager, 
        weather: WeatherModel) {
        print(weather.cityName)
        print(weather.temperature)
    }
  • //「WeatherManagerDelegate」プロトコルの実装
  • //「WeatherManagerDelegate」の受信者
  • //天気データが更新されると、didUpdateWeatherが発動し、更新データを受信

天気データ更新後、Tokyo,19.86とコンソールに出力されました。

更新された天気データをUIに表示

更新された天気データ(ここでは、温度)をUIに表示させてみましょう。

ところが、アプリを実行すると「must be used from main thread only」のエラーが出てクラッシュしてしまいました。

APIを使用して天気データを更新し、UIに表示するまでに時間がかかるため、アプリがクラッシュしたように見えてしまいます。そこで、この動作はバックグラウンドで実行させておいて、処理をメインに戻す必要があります。

DispatchQueueの中に先ほどのコードを入れると、問題は解決しました。

DispatchQueue
func didUpdateWeather(_ weatherManager: WeatherManager, 
    weather: WeatherModel) {

    DispatchQueue.main.async {
        self.temperatureLabel.text = 
         weather.temperatureString
    }
}

クロージャーの中にコードを入れたので、先頭に「self」をつけています。

この結果、天気イメージ、温度、都市名の更新データがUIに表示されるようになりました。

ViewControllerの機能拡張を分割して整理する

WeatherViewControllerには、「UITextFieldDelegate」と「WeatherManagerDelegate」という2つのプロトコルがあります。これらを分割して整理してみましょう。

STEP
UITextFieldDelegateの整理
  • 一番下に「extension WeatherViewController: UITextFieldDelegate {}」を作成する
  • 赤枠の4つのメソッドを移動する。
STEP
WeatherManagerDelegateの整理
  • STEP1で実施した赤枠の4つのメソッドが移動されていることがわかります。
  • 一番下に「extension WeatherViewController: WeatherManagerDelegate {}」を作成する。
  • 青枠の2つのメソッドを移動する。
STEP
整理後の状態

STEP2で実施した青枠の2つのメソッドが移動されていることがわかります。

STEP
「MARK」を使ってセクションを分ける

//MARK: – UITextFieldDelegate」と書き込むと、セクションが作成されます。

STEP
コードスニペットの作成

今後、MARKコメントを頻繁に使うことが考えられるため、コードスニペット(あらかじめ登録しておくと、再利用する場合の効率化が図れる)を作成しておきましょう。

作成したコードスニぺットを使用して、「WeatherManagerDelegate」のセクションを作成します

「ma」と書いただけで、MARKが選択できるようになりました。

位置情報から取得した天気データをUIに表示する

位置情報を取得する

STEP
プライバシーと位置情報の設定

位置情報を取得するためには、CoreLocationというパッケージをインポートする必要があります。
必要なコードも追記しました。

CoreLocationのインポート
import CoreLocation

class WeatherViewController: UIViewController {

    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationManager.requestWhenInUseAuthorization()
    }
}
  • locationManager:携帯電話の現在のGPS位置情報を取得する役割
  • requestWhenInUseAuthorization():位置情報の許可要求
info.plistの設定
  • info.plistに「Privacy – Location When In Use Usage Description」を選択し、Valueに「現在地の天気情報には、あなたの位置情報が必要です」を設定します。
  • アプリ起動時に、設定した内容が表示されます。

この設定をしておかないと、アプリが位置情報にアクセスするのを許可するために、プライバシーと位置情報の設定を確認する必要があります。

STEP
位置情報が更新されると、更新されたことを出力する
位置情報の更新確認
import CoreLocation

class WeatherViewController: UIViewController {

    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
// 「CLLocationManagerDelegate」の受信者
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestLocation()
    }
}

//MARK: - CLLocationManagerDelegate
//「CLLocationManagerDelegate」の実装
extension WeatherViewController: CLLocationManagerDelegate {

//位置情報が更新されると、didUpdateLocationsが発動
    func locationManager(_ manager: CLLocationManager, 
     didUpdateLocations locations: [CLLocation]) {
        print("ロケーションデータ更新しました")
    }

//位置情報更新が失敗すると、didFailWithErrorが発動し、エラー出力    
    func locationManager(_ manager: CLLocationManager, 
     didFailWithError error: Error) {
        print(error)
    }
}
  • 「CLLocationManagerDelegate」の実装
  • 「CLLocationManagerDelegate」の受信者
  • 位置情報が更新されると、didUpdateLocationsが発動し、”ロケーションデータ更新しました”出力
  • 位置情報更新が失敗すると、didFailWithErrorが発動し、エラー出力
STEP
現在地の経度(latitude)、緯度(longitude)を出力
現在地の緯度・経度出力
extension WeatherViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, 
     didUpdateLocations locations: [CLLocation]) {

        if let location = locations.last {
            let lat = location.coordinate.latitude
            let lon = location.coordinate.longitude
            print("経度: \(lat)")
            print("緯度: \(lon)")
        }
    }

天気データをUIに表示する

経度、緯度から現在地の天気情報を取得するには、

lat={lat}&lon={lon}

をURLに追記すれば良いことが確認できます。

https://openweathermap.org/current

UIに表示するには、既に確立している「都市名」→「URLに都市名追記」→「UI表示」の仕組みを利用します。

参考「都市名」→「URLに都市名追記」→「UI表示」
WeatherViewController(C)
extension WeatherViewController: UITextFieldDelegate {
    func textFieldDidEndEditing(_ textField: UITextField) {
        
    if let city = searchTextField.text {
        weatherManager.fetchWeather(cityName: city)
    }
    searchTextField.text = ""
}
WeatherManager(M)
struct WeatherManager {
    func fetchWeather(cityName: String) {
        let urlString = 
         "\(weatherURL)&q=\(cityName)"

        performRequest(with: urlString)
    }
}
位置情報」→「URLに経度緯度追記」→「UI表示」
WeatherViewController(C)
extension WeatherViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, 
     didUpdateLocations locations: [CLLocation]) {

        if let location = locations.last {
            let lat = location.coordinate.latitude
            let lon = location.coordinate.longitude
            weatherManager.fetchWeather(
                latitude: lat, 
                longitude: lon)
        }
    }
}
WeatherManager(M)
struct WeatherManager {
    func fetchWeather(latitude: CLLocationDegrees, 
        longitude: CLLocationDegrees) {
        let urlString = 
         "\(weatherURL)&lat=\(latitude)&lon=\(longitude)"

        performRequest(with: urlString)
    }
}

Swiftは、関数名が同じでもパラメータが異なれば、問題ない
func fetchWeather(cityName: String)
func fetchWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees)

Apple本社の天気情報がUIに表示されました

(完成)位置情報から天気データをUIに表示する

左上にあるボタンを押すと、現在地情報を取得します。
その現在地情報から天気情報を取得し、UIに表示してみましょう。

位置情報から天気データをUIに表示
  1. 左上のボタンを押すと位置情報を取得します。
  2. 位置情報が更新されると、「didUpdateLocations」が発動します。
  3. 現在地の経度、緯度情報を「weatherManager」に送付します。
  4. 「weatherManager」は天気情報を入手し、UIに表示するように指示します。

「locationManager」の中にある「stopUpdatingLocation()」について
アプリ起動後、「locationManager」が発動し、位置情報取得後、停止させています。
位置情報検索ボタンを押した時に、「locationManager」を発動させるためです。

これで、アプリ完成です。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次