📗

【swift】 クロージャの使い方 (たぶんすっごく基本)

2024/03/26に公開

クロージャとは????

処理のひとかたまりで、名前のついていないメソッドのようなもの
変数に保存したり、メソッドの引数として渡すことで実行できたりする

使用例

  • 変数に保存して利用する
  • メソッドの引数に記載して利用する (トレイリングクロージャ) 【メイン】

※ 上記以外にもありそうですが、すっごく基本ということでこの程度にしておきます。。。
※ 本記事では個人的に体感よく見かけるトレイリングクロージャをメインに記載します

変数に保存して利用する

let sum = { (x: Int, y: Int) -> Int in  
  return x + y
}

// 引数名を指定しない
let a = sum(1, 2) // 3

簡単に解説 (多分引用元の方がわかりやすいと思います)
クロージャは下記の形式で記載します。

{ (引数名:引数の型) -> 戻り値の型 in
    // 処理の実行
}
  • (x: Int, y: Int)の部分がクロージャの処理で使用する引数となっています。
  • -> Intの部分がクロージャで処理した結果の戻り値の型となります。
  • in以降に処理内容を記載します。

引用元:https://swift.codelly.dev/guide/クロージャ/#クロージャ式の引数

メソッドの引数に記載して利用する (トレイリングクロージャ)

実際に簡単なものを作って解説します

渡した先で処理を実行する

作ったもの

クロージャで渡した処理の結果をラベルに表示できるようにします

コード全体

// 与えた数値を足し算した後、labelとして表示する
showResult(x: 5, y: 2)

// labelとして表示するための処理は書いて、計算する処理 + 計算後の表示はplusにお願いしてる
func showResult(x: Int, y: Int) {
    plus(x: x, y: y, complete: { sum in
        label.text = String(sum)
    })
}

// 受け取った値を足し算して、その後にcompleteの処理を実行してる
func plus(x: Int, y: Int, complete: (Int) -> Void) {
    let sum = x + y
    complete(sum)
}

結果

解説

showResultの呼び出し

この部分が処理の始まりです。
渡した引数2つの足し算が実行されるようにします。

// 与えた数値を足し算した後、labelとして表示する
showResult(x: 5, y: 2)

showResultの処理内容

showResultの処理内容です。
ここまでは普通のメソッドの使い方と変わらず、plusというメソッドを呼び出しているだけです。
ただ、plusの呼び出し方がいつもと違っています...

// labelとして表示するための処理は書いて、計算する処理 + 計算後の表示はplusにお願いしてる
func showResult(x: Int, y: Int) {
    plus(x: x, y: y, complete: { sum in
        label.text = String(sum)
    })
}

plusの呼び出しについて
まず、普段よく使われるような基本の呼び出しの場合、下記のように「外部引数名: メソッドに渡す値」のように記載しています

func showResult(x: Int, y: Int) {
    plus(x: x, y: y)
}

plus側でxの変数名で扱われているものにshowResultxを、plus側でyの変数名で扱われているものに、showResultyを渡しています。

次に今回のようにクロージャも渡しているパターンです。

// labelとして表示するための処理は書いて、計算する処理 + 計算後の表示はplusにお願いしてる
func showResult(x: Int, y: Int) {
    plus(x: x, y: y, complete: { sum in
        label.text = String(sum)
    })
}

本来であればplus(x: x, y: y, complete: syori)と記載したいところを、syoriと記載されている部分を処理のひとかたまり(=クロージャ)に変えています。

plus(x: x, y: y, complete: {// ここに処理を記載する})

ただ、長くなってしまうとすごく見づらいので、改行して見やすいようにしています。

plus(x: x, y: y, complete: {
        /// ここに処理を記載する
    })

今回plusに渡している処理は、ラベルの値を計算結果になるように更新する処理を渡しています。
計算の処理が完了した後に、plusのメソッド内で更新まで実行してもらおうとしています。

plusの処理内容

showResultで呼び出された、plusの処理です。
こちらも普段と少し変わっている部分(complete: (Int) -> Void)があります。

// 受け取った値を足し算して、その後にcompleteの処理を実行してる
func plus(x: Int, y: Int, complete: (Int) -> Void) {
    let sum = x + y
    complete(sum)
}

complete: (Int) -> Voidに関して
ここは本来であれば、外部引数名: 型の形式で記載されることが基本かと思います。

func plus(x: Int, y: Int) {
    let sum = x + y
}

そのため、complete: 型と記載したいところですが、クロージャの場合は型の代わりにクロージャの引数の型と戻り値の型を記載します。
今回は、計算結果(Int)を受け取って、処理を完了(戻り値なし = void)となっています。

// 受け取った値を足し算して、その後にcompleteの処理を実行してる
func plus(x: Int, y: Int, complete: (Int) -> Void) {
    let sum = x + y
    complete(sum)
}

(おまけ) 渡す先のメソッドが複数にまたがる場合

コード全体

// 与えた数値を足し算した後、10倍してlabelとして表示する
showResult(x: 5, y: 2)
  
// labelとして表示するための処理は書いて、計算する処理 + 計算後の表示はplusにお願いしてる
func showResult(x: Int, y: Int) {
    plus(x: x, y: y, complete: { sum in
        label.text = String(sum)
    })
}

// 受け取った値を足し算して、10倍する処理 + 計算後の表示はtenTimesにお願いしてる
func plus(x: Int, y: Int, complete: (Int) -> Void) {
    let sum = x + y

    tenTimes(x: sum, complete: complete)
}

// 受け取った値を10倍したあと、completeの処理 (= labelに表示する処理)を実行する
func tenTimes(x: Int, complete: (Int) -> Void) {
    let result = 10 * x
    complete(result)
}

結果

解説

基本的には「渡した先で処理を実行する」の項目で解説したものと同じですが、
異なっているのがこの辺りになります。

// 受け取った値を足し算して、10倍する処理 + 計算後の表示はtenTimesにお願いしてる
func plus(x: Int, y: Int, complete: (Int) -> Void) {
    let sum = x + y

    tenTimes(x: sum, complete: complete)
}

// 受け取った値を10倍したあと、completeの処理 (= labelに表示する処理)を実行する
func tenTimes(x: Int, complete: (Int) -> Void) {
    let result = 10 * x
    complete(result)
}

plusで受けとったcompletetenTimesにそのまま渡しています。
showResultで渡したクロージャは、pluscompleteの変数に格納された状態になっているため、そのままtenTimesに渡すことが可能です。
「変数に保存して利用する」のイメージに近いです。

Discussion