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

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

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

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

クロージャ

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

Q&A

解決済

2回答

4470閲覧

クロージャを使ってReturnを使わないメリットとは?

Ren_Toyokawa

総合スコア15

Swift

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

クロージャ

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

0グッド

4クリップ

投稿2016/12/30 13:59

クロージャを使いReturnを使わないメリットとは
SwiftでTwitterクライアントを作ろうとしています。

Qiitaですでに作ってらっしゃる方がいらしたので、参考にしようと思ったのですが

Accountを取得する際や、TimeLineを取得する際、頑なにreturnは使わず、クロージャを使い、CallBackでAccountや、TimeLineを返しています。

実際のソースは下記のようなものです。

swift

1func getAccounts(callback: @escaping ([ACAccount]) -> Void) { 2 let accountType: ACAccountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter) 3 accountStore.requestAccessToAccounts(with: accountType, options: nil) { (granted: Bool, error: Error?) -> Void in 4 guard error == nil else { 5 print("error! \(error)") 6 return 7 } 8 guard granted else { 9 print("error! Twitterアカウントの利用が許可されていません") 10 return 11 } 12 13 let accounts = self.accountStore.accounts(with: accountType) as! [ACAccount] 14 guard accounts.count != 0 else { 15 print("error! 設定画面からアカウントを設定してください") 16 return 17 } 18 print("アカウント取得完了") 19 callback(accounts) 20 } 21}

このような場合ですと、処理が追いづらく、可読性が低いのではないか?と疑問に思ったのですが、クロージャを使う理由はどう言ったものがあるのでしょう。

Swiftのクロージャしかわからないのですが、一応、値のキャプチャなどは理解しているつもりです。

ちなみに、参考にさせていただいている記事はこちらです。
こちらの記事を貶めようと思っての投稿ではございませんので、何卒、ご了承ください
http://qiita.com/keisei_1092/items/32a96dbdb6bc394b0e8e#gettimeline

以上、ご回答のほど、よろしくおお願い致します。

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

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

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

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

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

guest

回答2

0

簡単に言うとメソッドの中に通信処理が入り非同期で実行される為、その値の取得後に処理を戻したいという事でクロージャーを使っているということですかね。

以下の処理は引数で受け取った値を足して戻すメソッドです、これは同期的に処理されるのでそのまま足した値が戻されます。

swift

1func add(value1: Int, value2: Int) -> Int { 2 return value1 + value2 3} 4 5// 呼び出し側 6let value = add(value1: 2, value2: 3) 7print(value) 8//=> 5

非同期処理がメソッドの中に入っている場合、普通にreturnで値を返すと通信処理を待っていないので結果が反映されない状態で返されます。

swift

1func getTweetCount() -> Int { 2 var tweetCount = 0 3 4 通信処理メソッド { count in 5 6 // 通信後に呼ばれるブロック 7 tweetCount = count 8 } 9 10 // 通信後の処理を待っていないので毎回 0 が返されます。 11 return tweetCount 12} 13 14 15// 呼び出し側 count は毎回0 16var count = getTweetCount() 17print(count) 18//=> 0

最後にクロージャーを使用した場合、非同期の通信処理が終わったところでクロージャーを実行して呼び出し元に処理を返しています。

swift

1func getTweetCount(callback: @escaping (Int) -> Void) { 2 var tweetCount = 0 3 4 通信処理メソッド { count in 5 6 // 通信後に呼ばれるブロック 7 callback(count) 8 } 9} 10 11 12// 呼び出し側 13getTweetCount { count in 14 15 // 非同期処理後に呼ばれる 16 print(count) 17} 18

投稿2016/12/30 14:30

編集2016/12/30 14:32
_Kentarou

総合スコア8490

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

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

Ren_Toyokawa

2017/01/18 23:31

より詳細なご回答、ありがとうございます。 クロージャの理解や、通信処理について知ることができました。
guest

0

ベストアンサー

例として挙げられているコードの場合、requestAccessToAccounts()メソッドは非同期的に実行されるので、結果が返ってくる前にメソッドが終了してしまうため、returnで通常の戻り値を返しても意図した通りに動きません。

非同期メソッドから値を返す方法はいくつかありますが、例のコードで行われているようにクロージャを渡して、実行完了のタイミングで呼び出してもらう方法や、Promiseオブジェクトを返して完了した後で実際の値が取得できるようにする、などがあります。

いずれにせよ、単にreturnを使いたくないからそうしているわけではなく、非同期メソッドの結果を扱わなければならないため、クロージャを利用することを選択した、ということだと思います。

投稿2016/12/30 14:09

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Ren_Toyokawa

2017/01/18 23:29

そうそうにご回答いただき、ありがとうございます。 返答遅くなり申し訳在りません。 その後自分で、色々調べ、腑に落ちました。 クロージャの特性に関して、まだまだ勉強が足りなかったようです。 非同期処理に関しても、デザインパターンなどを学ぶ必要があると気づくこともできました。 回答していただき、まことにありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問