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

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

新規登録して質問してみよう
ただいま回答率
85.37%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

iOS

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

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1553閲覧

完了ハンドラのクロージャー、他4点【Swift】

kazuki_user

総合スコア147

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

iOS

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

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/08/23 10:45

イメージ説明

番号ごとに4点質問です。

用語や矢印の向きが間違っていたら、ご指摘ください。

### ❶.(完了ハンドラの?)クロージャー

  • 紫色の下線spaceshipの、関係性がわかりません。

下記コードSpaceshipResponseCompletionにてEnterを押すと、

swift

1func getSpaceship(url: String) { 2 api.getSpaceship(url: url, completion: SpaceshipResponseCompletion 3}

以下のように、クロージャ形式に変形するのですが、

swift

1func getSpaceship(url: String) { 2 api.getSpaceship(url: url) { (Spaceship?) in 3 } 4}

Spaceship?の箇所に書くspaceship(←引数?)(紫、上)と、
in内のクロージャ(?)の直前のspaceshipとの関係性がわかりません。

なぜ、クロージャ{}の直前に引数名(?)が書かれるのかも、謎です。

swift

1 func getSpaceship(url: String) { 2 api.getSpaceship(url: url) { (spaceship) in 3 if let spaceship = spaceship { 4 self.setupView(spaceship: spaceship) 5 } 6 } 7 }

### ❷.クロージャにて、引数や定数の見分けが付かない

  • "引数"spaceshipは、Spaceshipクラスを「参照」しているのか。(オレンジ下)
  • "引数"spaceshipは、定数Spaceshipを「参照」しているのか。(オレンジ上)

以下の式をよく見かけますが、「引数の型」の箇所は、
クラス名」や「定数名」でも良いという事でしょうか。

(オレンジ、水色の下線参考。)

func 関数名 (引数1:引数1の型, ...) -> 戻り値の型 { return 戻り値 }

## ❸水色のspaceship

if letでアンラップ後、spaceshipに代入していることはわかるのですが
以下2点が分かりません。

  • 何を代入しているのか。
  • 水色上のspaceshipが、クロージャ内にてなぜ使われているのか。(水色下)

### ❹クロージャ内の、self

  • クロージャ内での関数呼び出しで、selfが必要な理由

質問は以上です。
お時間あるときに、ご返信頂けましたら幸いです????

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

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

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

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

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

guest

回答1

0

ベストアンサー

(1) 引数です

変換直後のSpaceship? は型を示しています。それをspaceshipと変数名に書き直すことで、spaceshipという名前で、Spaceship?型の値を受け取る、という意味になります。

SpaceshipResponseCompletionは、(SpaceShip?) -> ()という型のクロージャだと思います。引数としてSpaceship?型の値を一つ受け取り、戻り値はありません。
これは、関数で書けば
func X(_ s: Spaceship?) { code }
と似た様な形式です。
関数は、「関数名(引数名:引数の型) {コード}」という形ですが、クロージャでは、「{引数名 in コード }」という形になります。
inの前が引数です。一つなら一つ、複数あれば,で区切って繋ぎます。かっこはなくてもいいのですが、つけることが推奨されています。inのあとがクロージャの内部の実行すべきコードです。

in内のクロージャ(?)の直前のspaceship

ここは、何を指しているのかがわかりませんでした。
{}で囲まれた範囲がクロージャだと思うので、その直前にあるのは、一つ目の引数である(url: url)です。
このクロージャ自体は、getSpaceship関数に渡す二番目の引数です。

swift

1api.getSpaceship(url: url, completion: { (spaceship) in 2 if let spaceship = spaceship { 3 self.setupView(spaceship: spaceship) 4 } 5})

というように、書くこともできます。
SpaceshipResponseCompletionの部分を、{...}と、クロージャに置き換えているだけだということがわかるかと思います。

(2) 型です

func setupView(spaceship: Spaceship)
とあったら、spaceshipが引数名、Spaceshipが引数の型です。
spaceshipはSpaceShip型の定数です。

Spaceshipは定数ではなく、Spaceshipクラス(またはSpaceship構造体)を意味します。Spaceshipがクラスなら、spaceshipはSpaceshipクラスを参照します。Spaceshipが構造定なら、spaceshipはSpaceship構造体の値を持ちます。

以下の式をよく見かけますが、「引数の型」の箇所は、「クラス名」や「定数名」でも良いという事でしょうか。

クラス名、は型なのでOKです。定数はだめです。定数は値を変えられない変数であり、型ではないので引数の型に指定できません。

(3) アンラップした値です。

アンラップ、という言葉は、オプショナルな変数を、オプショナルでない型に変換するという意味です。
ここでは、Spaceship?型をSpaceship型に変換したものを、別の新しい定数であるspaceshipletで代入しています。
このif文の中では、アンラップしたSpaceship型のspaceshipしか見えません。従って、こちらが使われます。

(4) 循環参照を防ぐためです

クロージャの中では、selfが必要です。そういう決まりだと思えばよいです。
いちいちselfを書く必要があるのは、循環参照になっていないか、コードを書く開発者が気にするきっかけとなるように、selfが必要な仕様になっています。
Swift5.3でちょっと改善されます。

Swiftの仕様は公開されています。詳細はこちらをご参照ください。
関数の定義
クロージャの定義

投稿2020/08/23 14:34

eytyet

総合スコア803

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

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

kazuki_user

2020/08/24 01:55

ご丁寧な対応、どうもありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問