【Swift4】クロージャの使い方を整理する【超基本編】

# 概要
Swiftを勉強してて文法的に躓いたのがクロージャでした。頭を整理するためにSwiftにおけるクロージャの使い方をまとめてみます。自分用ですがお役に立てば幸いです。

# クロージャって何？
一言で言うと「無名の関数、あるいは関数のオブジェクトを利用した記述方法のこと」だと思っています。
正直正確な定義は分かりません。使いながら理解していきます。

# 基本となる書き方

クロージャの書き方はかなり動的です。そのため、以下の構文以外にも様々な書き方ができます。

```Swift
{ (引数名: 引数の型) -> （返り値の型) in
   //処理
}
```
引数と返り値の型を指定して実行したい文をin以下に記述することで、関数のインスタンスを利用できるようになります。

試しに使ってみましょう。

```Swift
// 三角形の面積を求める
let areaOfTriangle = { (base: Int, height: Int) -> Int in
    return base * height / 2
}
areaOfTriangle(2, 4) // 4
```

戻り値がある場合in以下にreturnを記述します。ただしreturnを記述する数が一つだけの場合は省略可能です。

```Swift
let areaOfTriangle = { (base: Int, height: Int) -> Int in
    base * height / 2
}
areaOfTriangle(2, 4) // 同じく4
```
# 引数・返り値の省略
クロージャは引数や返り値を省略して書くこともできます。
省略可能な状況は２パターンあるのでそれぞれ整理してみます。

## 1.ブロック内に文が一個の時
ブロック内の文が一個だけの時は引数と返り値を省略できます。
引数と返り値のどちらも記述しない場合、inの記述も必要なくなります。

```Swift
let closure1 = { () -> () in print("hoge") }  // 通常の書き方
let closure2 = { () in print("hoge") } // 返り値なし
let closure3 = { print("hoge") } // どっちもなし
```

## 2.型を推論できる時
クロージャの引数や返り値が明らかな場合は省略することができます。
以下の例ではクロージャを代入する定数に型を記述してやることで、クロージャ自体の引数と返り値の型を明確にしています。

```Swift
// 引数・返り値の記述あり
let titleLabel1 = { () -> UILabel in
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.tintColor = UIColor.blue
    label.text = "hogehoge"
    return label
}()

// 引数・返り値の記述なし
let titleLabel2: UILabel = { // () -> UILabel in この記述がいらなくなる
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.tintColor = UIColor.blue
    label.text = "hogehoge"
    return label
}()
```

# よく見るクロージャの活用例
ここまでクロージャの基本的な使い方をまとめました。
最後にクロージャがよく利用されるケースとして、通信の結果に応じて呼び出す処理を分ける書き方を実装してみます。
今回はQiitaのAPIを利用して記事を取得します。
http://qiita.com/api/v2/items
そして取得した記事をTableViewに表示させるだけのシンプルなアプリを作ります。

↓まずはAPIを利用するクラスから見ていきます。

```Swift
enum NetworkError: Error {
    case unknown
    case invalidResponse
    case invalidURL

}

class APIClient {
    static func request(success: @escaping ([Article]) -> (), // 通信成功時のクロージャ
                        failure: @escaping (Error) -> ()){    // 通信失敗時のクロージャ
        
        guard let url = URL(string: "http://qiita.com/api/v2/items") else {
            failure(NetworkError.invalidURL)
            return
        }
        
        let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
            if (error != nil) {
            failure(error!)
                return
            }
            guard let data = data else {
                failure(NetworkError.unknown)
                return
            }

            let decoder = JSONDecoder()

            guard let articles = try? decoder.decode([Article].self, from: data) else {
                failure(NetworkError.invalidResponse)
                return
            }
            success(articles)
        })
        task.resume()
    }
}
```
このクラスでは通信を行うメソッドを定義して、その引数に二つのクロージャを渡しています。
ポイントは@escapingがついてることです。
これをつけると引数に渡してるクロージャをrequestメソッドのスコープ内で利用できます。
以下の記事が参考になりました。
https://qiita.com/mishimay/items/1232dbfe8208e77ed10e

次にこのrequestメソッドをViewControllerで呼び出します。

```Swift

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
    var articles: [Article] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self

        // 通信のリクエストを送信
        APIClient.request(success: {(articles) in // 通信成功時のクロージャ
            DispatchQueue.main.async {
                self.articles = articles
                self.tableView.reloadData()
            }
        }) { (error) in
            print(error)
        }
    }
}

extension ViewController {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return articles.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = articles[indexPath.row].title
        return cell
    }
}
```

この部分でrequestを送り、通信の結果が成功ならTableViewをリロードしてます。

```Swift

APIClient.request(success: {(articles) in
    DispatchQueue.main.async {
       self.articles = articles
       self.tableView.reloadData()
    }
}) { (error) in
    print(error)
}
```

この時successの引数となっているarticlesは以下で部分で代入されてます。
ややこしいですよね。

```Swift
class APIClient{
    /* 処理　*/

    success(articles)

    /* 処理　*/
}
```

実行してみるとこんな感じになります。
<img width="300" alt="スクリーンショット 2018-12-25 2.58.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/311282/6aa969d7-17cd-e66e-767d-afbc50d75fb4.png">

# まとめ
- クロージャとは無名の関数、あるいは関数のオブジェクトを利用した記述方法のこと。
- クロージャは引数と返り値の型を指定して、処理をin以下に記述する。
- 「ブロック内に文が一個の時」「型を推論できる時」では型を省略できる。

ここまで読んで下さった方はありがとうございました！
クロージャはもっと深掘りすべき部分があると思うのでまた勉強したらまとめます！

※本記事は初心者が自分なりのまとめたものなのでその正しさは保証できかねます。もし記事の内容に誤りや改善すべき箇所を見つけられた場合はお手数ですがご指摘頂けると幸いです。