質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Q&A

解決済

2回答

338閲覧

【IOS】クロージャの引数で使われないのに書かれている引数について

jantyran

総合スコア14

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

0グッド

0クリップ

投稿2018/03/06 12:24

入門書を写経中に疑問に思って調べてみたものの、どうしても答えが見つかりませんでした。

クロージャーで引数が定義されているが、そこに書かれている引数名をクロージャー内で使用をしていない。

下記のコード内のクロージャーで 引数(action: UIAlertAction) が作られていますが、 しかしクロージャー内で使用をされていません。使われない場合エラーになると思うのですが、これはどうしてエラーにならないのでしょうか。

また、この引数は UIAlertActionが型で 引数名actionですよね。
となると、このクローシャーはどこかで呼ばれてこの引数に値が送られてきて使われることになるかと思うのですが、そもそもどこがどうやってこのクロージャーを呼ぶのかわからない。。。UIAlertActionがハンドラーの値に自分を入れ込んでクロージャーが動いているのか??
なんかこの辺がこんがらがってしまい、わからなくなります。

どなたか頭の悪い僕にもわかるよう説明いただけますと幸いです。
よろしくお願いします。

以下コード

if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { //create selection photolibrary let photoLibraryAction = UIAlertAction(title: "フォトライブラリー", style: .default, handler: { (action: UIAlertAction) in //up photolibrary let imagePickerController : UIImagePickerController = UIImagePickerController() imagePickerController.sourceType = .photoLibrary imagePickerController.delegate = self self.present(imagePickerController, animated: true, completion: nil) }) alertController.addAction(photoLibraryAction }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

関数を引数に取る関数を見てみると納得できると思います。
例えば

swift

1struct Hoge { 2 private(set) var fuga: Int 3 4 // fugaを使って何らかの計算をしてもらい新しいfugaを取得/設定する 5 mutating func hoge(calcutate: (Int) -> Int) { 6 7 fuga = calcutate(fuga) // 関数内部で引数の関数(クロージャ)を引数 fuga で呼び出す。 8 } 9} 10 11var h = Hoge(fuga: 10) 12 13h.hoge { (current: Int) -> Int in 14 return current * 5 15} 16 17print(h.fuga) 18// prints 50 19 20 21h.hoge { (old: Int) in // クロージャの引数ラベルはなんでもいい 22 return 4 // 引数は使わなくてもよい 23} 24print(h.fuga) 25// prints 4

投稿2018/03/07 01:01

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jantyran

2018/03/07 03:23 編集

回答ありがとうございます。 質問なんですが、一つ目のクロージャーの後に別のクロージャーを書いて同じprint文で呼び出していますが、クロージャーが上書きされているからこれができるということでしょうか。 また、このサンプルの理解は下記であっていますでしょうか。 一回目のh.hogeクロージャがhoge関数の引数calculateとして入れられる。 関数内でcalculateとしてクロージャが実行される。 fuga = calcutate(fuga)で fuga:10が クロージャの引数 current に渡される。 クロージャ内で5を掛けられてリターンされるために50が答となる。 二回目のクロージャが同じようにhoge関数のcalculate引数に渡されて、関数内でcalculateとしてクロージャが実行される。fuga:10がクロージャの引数old へ渡されるけれども使用されることなくリターンされる。
MasakiHori

2018/03/07 04:23

引数は関数内部で保存されません。使い捨てです。ので上書きとかはないです。 print(0); print(1); print(2); としても引数が上書きされたとは言わないです。それと同じです。
guest

0

ベストアンサー

そもそもどこがどうやってこのクロージャーを呼ぶのかわからない。

UIAlertActionがハンドラーの値に自分を入れ込んでクロージャーが動いているのか??

示されているコードにはありませんが、UIAlertActionをpresent(alert, animated:, completion:)で表示していて、順番はaddAction -> presentとなっていると思います。

つまり、表示前にあらかじめアプリがユーザーに示す選択肢の一覧をUIAlertControllerに、このActionが選ばれたらこのクロージャを、(あれば)別のActionならこのクロージャを、と追加しておいてからUIを表示し、その中でユーザーが選んだものに対応するActionのクロージャをUIActionControllerが(選ばれたActionとともに)呼んでくれる、という仕組みです。

使われない場合エラーになると思うのですが、これはどうしてエラーにならないのでしょうか。

順番があとになってしまいましたが↑をふまえて、
クロージャはUIAlertControllerが呼び出すわけですから、どんな引数を持つハンドラ(クロージャ)を受け取るかはAppleがUIAlertController/UIAlertActionを設計した段階であらかじめ決めておかないといけません。ですから、アプリがその引数を必要とするかしないかはわからないのです。
そのため、あとからそれを使用するアプリ側は先の設計に合わせる必要があるので、未使用でもエラーにはなりません。
アプリ側がそれを必要としないなら単純に_(アンダースコア)にしておけばいいですよ。

---------- 下の回答に対する追記です -------------------

クロージャについてなんか思い違いをされているように思うのですが、クロージャはもともとオブジェクトですから以下のように変数として持つことができます。

Swift

1let fun = {(action: UIAlertAction) in // クロージャをfunに代入 2 NSLog("Camera"); 3}; 4 5let cameraAction = UIAlertAction(title: "カメラ", style: .default, handler:fun) 6 7fun(cameraAction) // こんな感じで呼び出せる

ですから、UIAlertActionが渡したクロージャをそのまま持っていると思います。

UIAlertController内は実際の実装がどうなっているのかは知りませんが、以下のような感じだと思います。

Swift

1var actions : [UIAlertAction] = [] 2 3func addAction(action:UIAlertAction) 4{ 5 actions.append(action) 6} 7 8func actionSelected(index:Int) // indexは選択されたアクションのインデックス 9{ 10 var action = actions[index]; 11 action.handler(action) // ここで選択されたactionを引数としてアプリ側のクロージャが呼ばれる 12}

同じように _ に変えてしまっても良いのでしょうか?

Swiftだと未使用な引数は _ にしておけばコンパイラに未使用なのを明示することができるのでそれに合わせてもいいですし、クロージャの場合はactionでもエラーになりませんからどちらでもいいと思います。

投稿2018/03/06 14:32

編集2018/03/07 12:17
toki_td

総合スコア2850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jantyran

2018/03/07 03:48 編集

コメントありがとうございます! 認識としては、addAction()によって、UIAlertController ないに photoLibraryAction.handler()関数が作られて、その関数内にある引数へhandlerの値として設定したクロージャが渡されている。 そしてその引数が実行されることでこのクロージャーが実行される、ということであっていますでしょうか。 また、toki_tdさんの述べた理由でエラーにならないということであれば、下記のコード内の action: UIAlertAction 部分(cameraAction PhotoLibraryAction 双方ともの)は同じように _ に変えてしまっても良いのでしょうか? 以下もう少し全体を入れたコードになります。 ``` @IBAction func cameraButtonAction(_ sender: Any) { //choose camera of photoLibrary let alertController = UIAlertController(title: "確認", message: "選択してください", preferredStyle: .actionSheet) //avairable camera? if UIImagePickerController.isSourceTypeAvailable(.camera) { //create selection camera let cameraAction = UIAlertAction(title: "カメラ", style: .default, handler: { (action: UIAlertAction) in //up camera let imagePickerController : UIImagePickerController = UIImagePickerController() imagePickerController.sourceType = .camera imagePickerController.delegate = self self.present (imagePickerController, animated: true, completion: nil) }) alertController.addAction(cameraAction) } //available photolibrary? if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { //create selection photolibrary let photoLibraryAction = UIAlertAction(title: "フォトライブラリー", style: .default, handler: { (action: UIAlertAction) in //up photolibrary let imagePickerController : UIImagePickerController = UIImagePickerController() imagePickerController.sourceType = .photoLibrary imagePickerController.delegate = self self.present(imagePickerController, animated: true, completion: nil) }) alertController.addAction(photoLibraryAction) } } ```
toki_td

2018/03/07 12:17

上に追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問