【2024年4月】弊社では、基本リモートワークで一緒に成長してくださるメンバーを広く募集させていただいております。 詳細はこちら

【Swift】クロージャ(無名関数)の基本とクロージャを使った非同期処理について徹底解説!

【Swift】クロージャ(無名関数)の基本とクロージャを使った非同期処理について徹底解説!
ふくしま

考え事をしながら歩いていて電柱にぶつかったことがあります。ちょっと色々自信を失いかけました。株式会社メモリアインクのふくしまです!
今回は、Swiftにおけるクロージャー(無名関数)について解説していきます!

この記事を読んで分かること…
・クロージャって何?
・クロージャを使うとどんないいことがあるの?
・クロージャの基本的な使い方
・クロージャの応用

目次

クロージャ(無名関数)の基礎

クロージャ(無名関数)ってなに?

Swiftにおけるクロージャとは、「無名関数」と呼ばれており、自己完結型の何かしらの処理をコードブロック({ })で記述するためのSwiftの機能の一つです。
…って言われても、あまりイメージつかないかもしれませんが、徐々に紐解いていきますのでご安心ください!
とりあえず最初のうちは、「何かしらの処理の塊」= クロージャ(無名関数)ぐらいのイメージで大丈夫です。

メソッド(関数)と何が違うの?

「何かしらの処理」と聞くと真っ先にメソッド(関数)を思いつくかと思いますが、そのメソッド(関数)との違いはなんなのでしょうか?
クロージャ(無名関数)とメソッド(関数)の構文を見比べるとその違いが理解できると思います!

🔸メソッド(関数)の構文

func 関数名(引数) -> 戻り値の型 {
   // コードブロック
}

🔸クロージャ(無名関数)の構文

{ (引数) -> 戻り値の型 in
    // コードブロック
}

メソッド(関数)の定義では、関数名を定義した上で、コードブロック内で処理を書きます。
定義したメソッドは、関数名()で呼び出し元から呼び出します。
一方で、クロージャはいきなりコードブロック内で処理を書き始めます。このことから”関数名を持たない処理”という意味で「無名関数」と呼ばれています。
関数名を持たないことで、処理自体を変数に格納したりメソッド(関数)の引数にすることができるのがクロージャの特徴と言えます。

クロージャの基本的な使い方

それでは実際に、配列のsortメソッドをクロージャーを使用してカスタマイズする例を使ってクロージャの使い方について学びましょう!
sort メソッドは、配列の中身の順番を降順・昇順に入れ替えてくれるSwift標準のメソッドです。

var numbers = [20, 10, 40, 30]

numbers.sort(by: <)

print(numbers)

出力結果:
[10, 20, 30, 40]

sortメソッドの引数by:に比較演算子を入れることで、内部でよしなに配列Arrayの中身を見て並び替えてくれる便利なメソッドですが、今回はこちらの引数をあえてクロージャーで書いてsortメソッドをカスタムしてみます。

var numbers = [20, 10, 40, 30]
numbers.sort(by: { (number1: Int, number2: Int) -> Bool in
    return number1 < number2
})

sortメソッドの引数にクロージャーを指定しています。
クロージャーの部分を抜き出してみましょう。

{ (number1: Int, number2: Int) -> Bool in
    return number1 < number2
}

// クロージャ(無名関数)の構文
{ (引数) -> 戻り値の型 in
    // コードブロック
}

クロージャ部分の説明:
・引数:(number1: Int, number2: Int)
sortメソッドが呼び出された時、配列の値が入ってきます。

・戻り値の型:-> Bool
このクロージャーの戻り値がBooean型(truefalse かの論理演算子)を返すことを宣言します。

in キーワード
引数、戻り値の定義の完了と処理の始まりを示します。
inキーワード以降に実際の処理を定義します。

・処理:return number1 < number2
第一引数と第二引数の値を比較して、trueかfalseで返します。
処理が実行されるタイミングは、sortメソッドが呼び出され、引数に値がセットされた瞬間です。

非同期処理

Swiftの非同期処理では、処理が完了した後の動作をクロージャとして定義することがよくあります。

// 非同期処理の定義
func fetchData(completion: @escaping (Data?, Error?) -> Void) {
    // ...
    // 非同期処理でデータをフェッチする処理
    // ...
    completion(fetchedData, nil)
}

// 非同期処理(@escaping属性のついたクロージャ)完了後の処理
fetchData { data in
    print("非同期処理の結果: \(data)")
}

この例では、fetchData関数は非同期にデータを取得し、完了時にクロージャを呼び出します。このクロージャはデータとエラー情報をパラメータとして受け取ります。
@escapingは、クロージャが関数の引数として渡される際に使用される属性です。この属性は、クロージャが関数のスコープを超えて後で実行される可能性がある(例:非同期処理)ことを示します。
非同期処理が完了し、completion(fetchedData, nil) が呼ばれると、fetchData関数の呼び出し先に定義した非同期後の処理を呼び出します。

クロージャの利点と欠点

利点

  • コードの簡潔性: クロージャを使用することで、関数やメソッドの引数として直接コードブロックを記述でき、コードが読みやすくなります。
  • 柔軟性: クロージャはパラメータと戻り値を持つことができ、非同期処理やコールバック処理において高い柔軟性を発揮します。

欠点

  • キャプチャリストの複雑さ: クロージャが外部の変数をキャプチャする際、メモリ管理に注意が必要です。特に、循環参照が発生するとメモリリークの原因になり得ます。
  • 読みづらさ: 短いクロージャは便利ですが、長いクロージャや複雑なロジックを含むクロージャは読みづらくなることがあります。

まとめ

Swiftにおけるクロージャの使い方を理解し、適切に活用することで、より効率的で読みやすいコードを書くことができます。少々複雑ですが、何回も記事を読んで理解しておきましょう!
この記事が皆様の開発ライフの一助になれれば幸いです!

ふくしま

この記事があなたのスキルアップに役立ったなら、次のキャリアステップを踏み出す絶好の機会かもしれません。エンジニアとしてのさらなる成長と挑戦を求めるなら、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
をオススメします!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメント一覧 (2件)

コメントする

目次