【Swift】クロージャってどう使うの?【非同期通信】
ようやく頭の中でストンと解釈できた気がしたので、忘れないようにメモを残しておきます。
基本の型
{
( 仮引数: 型 ) -> 型 in
処理
}
基本の形で見てもちょっとわかりづらいですよね。
var closure = { () -> () in
print("Hello")
}
closure() // 出力 "Hello"
こうすると関数っぽくなってわかりやすくなります。
非同期通信に利用する @escaping
汚いコードで申し訳ないのですが、自分の作ったクロージャの一部抜粋です。requests の第一引数に文字型、第二引数に @escaping 属性をつけたクロージャを代入しています。
@escaping をつけていると引数が確定していなくても、関数内のコード処理が先に行われます。
この処理においては、コード下部にある completion() クロージャの引数が確定した時点で、第二引数の completion の値が確定します。
func requests(sentence: String,
completion: @escaping (_ rubyCharacter: String) -> Void) {
// リクエスト情報
let requestsData = RequestsData(sentence)
// リクエスト送信
AF.request(requestsData.requestUrl,
method:.post,
parameters: requestsData.parameters)
.responseJSON { response in
do {
// JSON取得
let responseData = try JSONDecoder().decode(ResponseData.self, from: response.data!)
// 取り出して変換
let rubyCharacter = responseData.converted
completion(rubyCharacter)
} catch {
//error処理
}
}
}
第2引数の completion が確定するということは、requests 関数から代入するはずだった completion も確定します。それによって requests 関数の仮引数が確定し、代入処理が行われます。
第2引数はクロージャですので、[仮引数, 戻り値, 処理] が書くことができました。代入処理ということはクロージャ式が評価されるということなので、この時点でクロージャの処理が行われます。(これが非同期処理)
requests(sentence: textData,
completion: { [weak self] (rubyCharacter: String) -> Void in
self?.outputCharacter.text = rubyCharacter
}
わかりづらかった箇所
// なんでこれで値確定すんの???
completion(rubyCharacter)
初めは本当にわかりづらかったです…
しかし、下のように書くことによって理解を深めました。
var completion = { (String) -> () in print("Hello") }
completion(String) // 出力 Hello
こうやって書けば、仮引数の completion に代入した時に、式が成立するようになり、in の後に続いている処理も行われるのも納得できました。
最後に
swift のクロージャには接尾クロージャという、書き方を省略できる性質があります。これがまた、読むのが大変で困ってしまいます…(全部わかっていれば余裕なのだろうだけれど)
でもこれができれば、処理の多くが見えるようになるし、邁進するだけだなとしみじみ感じております。
ここまで見ていただきありがとうございました。
これからもぼちぼち更新していくのでよろしくお願いします!
ツイッターもやっていますのでぜひフォローしてください。
hoya
https://twitter.com/hoya_vba
この記事が気に入ったらサポートをしてみませんか?