Blog

Swift completionHandlerについて

Swiftの completionHandlerについて説明します。

Swiftの勉強方法まとめてみました。初学者の方はまずこちらを御覧ください。

クロージャとは?

クロージャーがわからないと、completionHandlerも理解できません。
クロージャーについて、理解がおぼつかない方は、まずこちらを御覧ください。

クロージャーについて、なるべくわかりやすく説明。

通常関数は、引数を定義して利用します。


引数がnilだったりしたら当然使えません。

どうしてクロージャーが必要かというと、グーグルマップをイメージしてください。

住所を入れないと、そもそも地図は表示できない。
住所を入力して、初めてその場所が表示されます。
住所が入力されたときに、初めて、関数内のクロージャーが実行されて、MAPを表示するイメージです。
ですから、住所が入力されるまで(引数が渡されるまで)は、その関数のクロージャー部分は、実行されなません。
大変便利ですね。
WEBなどでよく利用されるものです。
イベントドリブンといいます。何かのトリガーで関数が動く。


Swiftも同じような仕組みを備えています。それがクロージャーであり、completionHandlerというわけです。

説明してもわかりにくいので、実際のジオコーディングのコードから説明します。

    //テキストフィールドに入力された住所 nilチェックをしています。
        if let addressWord = address.text {

            //CLGeocoderのインスタンスを生成
            let geocoder = CLGeocoder()

            //geocodeAddressStringは住所を入れる、その住所でもってhttp通信で帰ってきた値を利用して地図を描画
            //ここでcompletionHandlerを利用 引数にplacemarks, errorを渡しているがそんな物は無い。appleMAPのAPIが返してくれて初めて存在する
            geocoder.geocodeAddressString(addressWord, completionHandler: { (placemarks, error) in

                //もしplacemarksがAppleMAP返却されたら配列locationsに詰め込もう!
                if let locations = placemarks {

                    //locations配列の初めのものが目的の住所の座標値
                    if let firstlocation = locations.first {
                        if let location = firstlocation.location {

                            //目的地の座標値をtargetCordinateに入れよう
                            let targetCordinate = location.coordinate

                            //チェックのためにコンソールに出力
                            print(targetCordinate)

ここで大切なのは、下記部分です。{ }の中の (placemarks, error) がクロージャーにわたす引数です。 in の後がクロージャーの処理です。

 geocoder.geocodeAddressString(addressWord, completionHandler: { (placemarks, error) in

                //もしplacemarksがAppleMAP返却されたら配列locationsに詰め込もう!
                if let locations = placemarks {

ユーザーが目的地を入力したら、その場所を返却する関数です。

当然ですが、ユーザーがどんな位置情報を入力するか?は実行されたときでないとわかりません。addressWord はわからないわけです。でもコードは書いておかないと当然動きません。

で、クロージャーの登場です。クロージャーは、引数が準備されたときに、実行されます。ですから、このような位置情報を返却する、ジオコーディングなどは大変利用価値が高いですし、最近のアプリは、iOS内部で完結するものは殆どありません、WEBと接続する必要があります。ですから、クロージャーは、必須です。

placemarksはアップルマップに問い合わせをしたときに、目的の座標値等のデータが返却されます。アップルのPAIから値が返却されます。

その座標値を取り出して、マーカーを表示するわけです。

placemarksは、引数として利用されていますが、アップルマップから値が返却されないと当然値はアリません。値があるときに、実行されますので、クロージャーは大変重宝する仕組みです

UserNotificationの例で、completionHandlerを確認してみよう!

UserNotificationとは、アプリのアイコンの右上につくバッジを管理する仕組みです。


なにかのアプリの情報の更新があると、その数などを、Userに教えてくれます。

しかしそれを表示するには、ユーザーの許可が必要です。そのアラートメッセージを表示させます。

そこでusreが了解したときに初めて通知(バッジ-数字のマーク)を表示できます。ちなみにアラートメッセージは以下のようなものです。

ここでもクロージャーを利用します。コードを見てみましょう。

//5秒後にpush通知
//通知許可
UNUserNotificationCenter.current().getNotificationSettings{

//ここでもクロージャーを利用 settingsが返却されるのを待つ 無いときはクロージャーは実行されない。
  (settings) in

//もしUserが .autorized(許可しているなら)
  if(settings.authorizationStatus == .authorized){
    self.push()
  }else{
    UNUserNotificationCenter.current().requestAuthorization(options: [.sound, .badge, .alert], completionHandler:{
     //ここがクロージャー (granted, error) が引数 in 以下が実装部
     //ここでユーザーが許可するかどうか尋ねています。trueは一つ以上OK,falseはすべて拒否が帰ります。
     (granted, error) in

     //もしerrorがあるなら
     if let error = error{
//errorをデバッグエリアに出力しなさい
       print(error)
     }else{

     //もしgrantedがあるなら(Userが許可したら=値が返却されたら)
       if(granted){
       //配列に追加しなさい
         self.push()
       }
     }
  })
 }
}

ここでは、アプリケーションに通知するために UNUserNotificationCenter クラスを利用しています。

例えて言うなら

UNUserNotificationCenterは郵便局
Notification は送られる手紙

ローカル通知やリモート通知でも同じ要領で利用されます。

では、関数定義を見てみましょう

func requestAuthorization(options: UNAuthorizationOptions = [],
     completionHandler: @escaping (Bool, Error?) -> Void)

ここでのポイントは下記部分です。

 completionHandler:{
     //ここがクロージャー (granted, error) が引数 in 以下が実装部
     //ここでユーザーが許可するかどうか尋ねています。trueは一つ以上OK,falseはすべて拒否が帰ります。
     (granted, error) in

     //もしerrorがあるなら
     if let error = error{
//errorをデバッグエリアに出力しなさい
       print(error)

  //もしgrantedがあるなら(Userが許可したら=値が返却されたら)
       if(granted){
       //配列に追加しなさい
         self.push()
       }

ここでは同じように、(granted, error)completionHandlerの引数として渡されています。

上記アラート画面でuserがOKボタンを押したときに初めて、granted以下が実行されます。

completionHandlerがNotificationなどで非常によく使われます。

例えば、”写真へのアクセスを許可しますか?”などのアラートです。


ユーザーは認可を許可または拒否することができ、システムはユーザーの応答を保管して、このメソッドへの後続の呼び出しでユーザーに再度プロンプトを出さないようにします。

ユーザーがだめというと、falseが帰り、利用できなくなります。

このようなときにもcompletionHandlerが利用されます。

だって、まだユーザーがどんな返事をするか、事前にはわからないですよね。

基本completionHandlerはクロージャーなので、値(引数)が入ってきたときに実行されます。
とても便利ですね。

では、また!


一つ前の記事 Swift テキストフィールドをアラートに表示する
次の記事 要件定義の前についての考察