🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Swift

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

Q&A

解決済

1回答

537閲覧

補完されるクロージャーとエンターキー後に生成されるコードの関連性

momokoko

総合スコア38

Swift

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

0グッド

0クリップ

投稿2021/02/02 10:10

Udemyでswiftを勉強中です。
クロージャーについて理解しようとしています。

① ②:自分の理解が正しいか見てほしい
③~⑤:質問の回答をしてほしい

以下の①と②のコードの理解が正しいかと③~⑤について解説をお願いしたいです。

※質問に付随されると思われるUserService構造体とUserカスタムクラスは最後の方にあります。

① func fetchUser() { UserService.fetchUser(completion: (User) -> Void) }

①引数にUser型を取る、戻り値はない。

↓上記の補完にエンターを押すと下記のコードが生成されます。

② func fetchUser() { UserService.fetchUser { (<User>) in <code> } }

<User>にはUser型のプロファイルを入れる必要がある

↓実際にUdemyの先生が書いたコード

func fetchUser() { UserService.fetchUser { (user) in self.user = user } }

<code>内には返り値があるないで書く内容にどのような変化があるのでしょうか。
リンク内容
上記の記事では、
返り値あり:return
返り値なし:print
となっていますが、今回の場合は返り値なしパターンなのですが、printはありません。

以下質問です。
self.user = userがprintに代替されるものだとして、なぜ代替できるのか?
⑤返り値ありではself.user = userが書けないのか、またその理由はなぜか。

よろしくお願い致します。

// UserService.swift import Firebase struct UserService { static func fetchUser(completion: @escaping(User) -> Void) { guard let uid = Auth.auth().currentUser?.uid else { return } COLLECTION_USERS.document(uid).getDocument { snapshot, error in guard let dictionary = snapshot?.data() else { return } let user = User(dictionary: dictionary) completion(user) } } }

/// Userのカスタムクラス

// User.swift import Foundation struct User { let email: String let fullname: String let profileImageUrl: String let username: String let uid: String init(dictionary: [String: Any]) { self.email = dictionary["email"] as? String ?? "" self.fullname = dictionary["fullname"] as? String ?? "" self.profileImageUrl = dictionary["profileImageUrl"] as? String ?? "" self.username = dictionary["username"] as? String ?? "" self.uid = dictionary["uid"] as? String ?? "" } }

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

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

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

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

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

guest

回答1

0

ベストアンサー

###(1)

Swift

1 func fetchUser() { 2 UserService.fetchUser(completion: (User) -> Void) 3 }

引数にUser型を取る、戻り値はない。

completion の後に User型の引数を一つ取り、戻り値がない関数を一つ渡すという意味です。
あるいは、User 型の引数を一つとり、戻り値がないクロージャを渡す、という解釈も可能です。

なので、「引数にUser型を取る」のではなく、「引数に User 型を一つ取り、戻り値がない関数、もしくはクロージャを渡す」という意味になります。

###(2)

Swift

1 func fetchUser() { 2 UserService.fetchUser { (<User>) in 3 <code> 4 } 5 }

<User>にはUser型のプロファイルを入れる必要がある

プロファイル、という用語をどのような意図で使われているのかわかりませんが(Udemy でそう教えているのであれば、プロファイルではなくパラメータと言っているのではないでしょか)、ここには仮引数名を入れます。

なので、下記のコードは

Swift

1↓実際にUdemyの先生が書いたコード 2 func fetchUser() { 3 UserService.fetchUser { (user) in 4 self.user = user 5 } 6 }

UserService.fetchUser というメソッドが実行された結果得られた値が、user という変数に代入して渡される、という流れになります。

色々な場所でuserという同一の変数名が使われているので混乱されている可能性もありますが、(user) の部分はあくまでも「仮引数名」なので、user という名前にこだわる必要はありません。

たとえば、

Swift

1 func fetchUser() { 2 UserService.fetchUser { (value) in 3 self.user = value 4 } 5 }

とかいても何ら問題はありません。

###(3)

<code>内には返り値があるないで書く内容にどのような変化があるのでしょうか。
リンク内容
上記の記事では、
返り値あり:return
返り値なし:print
となっていますが、今回の場合は返り値なしパターンなのですが、printはありません。

Swift

1 func fetchUser() { 2 UserService.fetchUser(completion: (User) -> Void) 3 }

のコードを思い出して欲しいのですが、completion で与えるのは「戻り値がない(Void)」関数、もしくはクロージャとなっています。

なので、そこで与える関数には return は必要ありません。

ちなみに、リンク先のテキストやクロージャの効果を確かめるためあのような書き方をしてありますが、本来は引数のあるクロージャ、無いクロージャで区別して説明すべきなので適切ではないと思います。

###(4)

self.user = userがprintに代替されるものだとして、なぜ代替できるのか?

代替されていません。
ただ単純に、代入を行っているだけです。

###(5)

返り値ありではself.user = userが書けないのか、またその理由はなぜか。

Swift

1self.user = user

は単なる処理ですから記述することは可能です。

一方、戻り値ありのクロージャを指定した場合には、当然その内部、あるいはクロージャの代わりに渡す関数で return で何らかの値を戻さなければコンパイルエラーとなります。


Google検索は便利なのですが、検索結果として表示する内容の正当性までは判断しません。
最近は中身がなく、あるいは適当だけど文書構造が正しいという理由でトップに出てくる不正確な記事が増えてきて、むしろ有害になりつつあります。

日本語で適当な説明を書いてあるページを読むくらいであれば、英語で正確に説明された、しかも公式のドキュメントを読まれたほうがいいと思います(英語の講座を購読されているのであれば、さほど難しい内容ではないと思います)。

今回の件に相当する公式なドキュメントは下記になりますので、ぜひご一読ください。


追記

クロージャの便利さと機能がわかりやすい例を考えていたのですが、どうも駄作しかできませんので、とりあえずサンプルを一つ提示します。

このコードを Playground で実行し、いろいろご自身で手を加えて実行して、どのような動作をするのか確かめてみるのも一つかもしれません。

とりあえず言えることは、
現時点で学ばれているクロージャの利点は、提供されているメソッドを、その利用者独自の柔軟性をもって拡張できる点にある、ということです。

Swift

1import Foundation 2 3func fetchUser() { 4 print("太郎") 5} 6 7func fetchUserWithKun() { 8 print("太郎くん") 9} 10 11func fetchUserWithHandler(completion: (String) -> Void) { 12 let name = "太郎" 13 14 completion(name) 15} 16 17// 決まりきった名前しか表示できない 18fetchUser() 19 20// 「くん」を付ける関数を作る 21// でも、この方法だと拡張性に欠ける 22fetchUserWithKun() 23 24 25// クロージャを使うことで拡張性を高める 26// 一つのメソッドに対して、さまざまな処理方法を追加できる 27 28// fetchUserWithHandler で取得した名前に対して「さん」づけで表示できる 29fetchUserWithHandler { name in 30 print("with closure: (name) さん") 31} 32 33// fetchUserWithHandler で取得した名前に対して「くん」づけで表示できる 34fetchUserWithHandler { name in 35 print("with closure: (name) くん") 36} 37 38// fetchUserWithHandler で取得した名前に対して「Mr」の敬称をつける 39fetchUserWithHandler { name in 40 print("with closure: Mr. (name)") 41}

投稿2021/02/02 11:56

編集2021/02/02 12:45
TsukubaDepot

総合スコア5086

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

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

momokoko

2021/02/02 12:46 編集

毎度、ありがとうございます。 解説わかりやすかったです。 公式なドキュメントありがとうございます。 恥ずかしながらぼくは英語が読めません。 翻訳機能を使って読んでみますね! 英語のUdemyの講座を取った理由は、インスタグラムみたいなアプリを作ってみたかったんですが、それをまさにやっている講座だったので受けました。 1年前くらいに、基礎コース(https://www.udemy.com/course/ios14-iphone-ios-boot-camp/) は受けていますが、講座では理解できないコードがたくさん出てきて苦戦中です。。
TsukubaDepot

2021/02/02 12:47

例題を追加しましたので、これをいじってみると少しは理解が促進できるかもしれません。
TsukubaDepot

2021/02/02 12:49

技術文書は実はあまり難しい英語は使われていないので、初めて取り掛かる技術であれば日本語でも英語でも、わからない時はさっぱりわからないので気にする必要はないのですが、やはり日本語で信頼できる文法本は一冊携えておく必要はあると思います(主観です)。 専門書だと3000円は超えることも多いですが、Udemy の割引セールで3講座買ったと思えば、実はそれほど高くないわけなので、ぜひ検討されることをお勧めします。
momokoko

2021/02/02 12:50

クロージャのサンプルまで作成していただきありがとうございます!! やってみます!
momokoko

2021/02/02 12:55

以前、アドバイス頂いた文法書に関してなんですが、 https://www.amazon.co.jp/Swift%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-%E7%9B%B4%E6%84%9F%E7%9A%84%E3%81%AA%E6%96%87%E6%B3%95%E3%81%A8%E5%AE%89%E5%85%A8%E6%80%A7%E3%82%92%E5%85%BC%E3%81%AD%E5%82%99%E3%81%88%E3%81%9F%E8%A8%80%E8%AA%9E-WEB-PRESS-plus/dp/4774187305 この文法書を持っています。クロージャーの解説を読んでも理解できませんでした。 この質問のご回答によりクロージャーに関して少し理解が進んだように思えるので、いま一度読んでみようとは思いますが、TsukubaDepotさんの目線で僕のレベルに合った文法書などありましたらご紹介頂けると幸いです。
TsukubaDepot

2021/02/02 12:59

上記の書籍はやや高度ですね。 「実践」と書かれているだけあって、かなり抽象的な概念も数多く含まれています。 その一方、「実践」はあんな複雑なコードをここまで抽象化できるんだ、という発見もあります。 Swiftにおける文法本で信頼のおける本は選択肢は少なく、あとひとつは「詳解 Swift 第5版 」だと思います。 この本も、ある程度一般的な言語の基礎知識は必要としていますが、全体的に実験的なコードも多く、体験的に学習できるので、余裕があれば購入を検討されてもいいかもしれません。 https://amzn.to/3tiftyn
momokoko

2021/02/02 13:28

ご紹介ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問