swift その2、24日目です。(。・ω・)ノ
(1日遅れてしまいまして申し訳ありません。。)
※あくまでも取っ掛かりという目的で閲覧ください。m(_ _)m
⭐️去年のアドベントカレンダーではDelegateについて書きました⭐️
https://qiita.com/narukun/items/326bd50a78cf34371169
swift初心者の多くは苦戦するClosure。
delegateの次にぶつかる壁と言っても良いでしょう。
私もその1人で、
分かりにくい分たくさんのClosureの記事が存在していますが、
ありとあらゆる「わかりやすい!簡単!Closure」の記事を見てもなかなかピンときませんでした..orz
(delegateに続き、私の理解力の問題..)
ということで、
世に溢れているわかりやすいClosureの説明を見ても理解できなかった私が、
イラストを使ってさらにわかりやすく、
Closureの基本を書いていきたいと思います。
1.そもそもなぜ理解できないのか?
まず、そもそもなぜClosureの理解が難しいのか。
端的に言いますと、結局のところ
「で、何ができるの?😰😰」
「使いどころがわからない..😰😰」
ってところに尽きるのかなと思います。
それだと結局、
「サンプルコード見て書き方は分かったよ、うん(でも自分で流用できない)」
= 理解できていない
となってしまうので、そこを紐解く必要があります。
2.Closureとは?
WikiPediaで調べると、
クロージャ(クロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。いくつかの言語ではラムダ式や無名関数で実現している。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。
..とかなんとか書いてありますが...😭とりあえずまずは、
「ブロックで囲んだ中にある処理を実行する自己完結型の機能」
くらいの認識で大丈夫です。
3.例文
まずクロージャの基本的な書き方は、
{ (引数) -> 戻り値の型 in
処理
}
こんな感じ。
◆基本的な使い方:関数を使わずにインスタンス化することができます。
- パターン1:戻り値がない場合
var sample = { (num1: Int, num2: Int) -> Void in
print(num1 + num2)
}
//クロージャの実行
sample(1, 2) // print文としての「3」が取れる
- パターン2:戻り値がある場合
var sample2 = { (num1: Int, num2: Int) -> Int in
return num1 + num2
}
//クロージャの実行
sample2(1, 2) // そのままの「3」が取れる
4.具体例
もう少し、実践的な使い方を見てみようと思います。( *・ω・)ノ
作るもの
こんなの。
それぞれの猫のボタンをタップすると、各時間遅れで背景の色が変わるようにします。
ポイント
これを実現するためのポイントは、
「処理遅延をさせて、遅延が完了した後に処理を実行させる」
ということで、この部分でクロージャを使ってみます( *・ω・)ノ
コード
実際に書いてみるとこんな感じですね。
import UIKit
class ViewController: UIViewController {
// 遷移ボタンタップ
@IBAction func buttonTap(_ sender: UIButton) {
self.pageTransition()
}
// 遷移2ボタンタップ
@IBAction func button2Tap(_ sender: UIButton) {
self.pageTransition2()
}
// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Private Method
// 処理1
func pageTransition() {
pagingProcess(time: 1, complete: self.tapButtonProcessing)
}
// 処理2
func pageTransition2() {
pagingProcess(time: 2, complete: self.tapButtonProcessing2)
}
/// 前処理
///
/// - Parameters:
/// - time: 遅延時間
/// - complete: 完了後のメソッド呼び出し
func pagingProcess(time: Double, complete: @escaping () -> Void) {
// 処理遅延
DispatchQueue.main.asyncAfter(deadline: .now() + time) {
complete()
}
}
// 色を変更
func tapButtonProcessing() {
view.backgroundColor = UIColor.red
}
// 色を変更2
func tapButtonProcessing2() {
view.backgroundColor = UIColor.blue
}
}
5.解説
アメリカ猫ちゃんのボタンを押した時、
引数がtime: 1, complete: self.tapButtonProcessing
で下記のメソッドを呼んでいます。
func pagingProcess(time: Double, complete: @escaping () -> Void) {
// 処理遅延
DispatchQueue.main.asyncAfter(deadline: .now() + time) {
complete()
}
}
completeがクロージャになってますね(◎_◎;)
流れとしては、
- ボタンをタップする
- 遅延時間とその後実行する処理メソッドを引数で渡す
- asyncAfterで処理遅延し、完了後、引数で持つcomplete()を呼ぶ
- completeで渡していた、self.tapButtonProcessing()のメソッドが実行される
ですね。
これって、引数でクロージャが使われてるから、ん????ってなっちゃいそうですが、
上記で書いた、
- パターン1:戻り値がない場合
var sample = { (num1: Int, num2: Int) -> Void in
print(num1 + num2)
}
//クロージャの実行
sample(1, 2) // print文としての「3」が取れる
と大して変わらないですよね。
もっと複雑になっても、この流れをイメージできれば理解できるかと思います。
(ちなみに、@escaping
はswift3からクロージャを非同期的に実行するときに必要になったため書いています。)
#6.まとめ
基本的にクロージャはコードの簡略化がメインの目的のようです。
私もまだうまく使いこなせていないですが積極的に使っていきたいですね。
すごく短くなってしまいました💧が、ありがとうございました。m(_ _)m