

下のコードの  
`signIn(withEmail:link:)`メソッドの`{}`内の処理の流れがよく分かりません。  
`self.hideSpinner{}`は必ず実行されるのしょうか？  
このような構文は何と呼ばれるものですか？

[code]

    if let email = self.emailField.text {
        showSpinner {
            // [START signin_emaillink]
            Auth.auth().signIn(withEmail: email, link: self.link) { (user, error) in
                // [START_EXCLUDE]
                self.hideSpinner {
                    if let error = error {
                        self.showMessagePrompt(error.localizedDescription)
                            return
                    }
                    self.navigationController!.popViewController(animated: true)
                }
                // [END_EXCLUDE]
            }
            // [END signin_emaillink]
        }
    } else {
        self.showMessagePrompt("Email can't be empty")
    }
    
[/code]


CC BY-SA 4.0
2019-07-19T06:34:30.583
56742
2019-07-23T03:26:58.967
2019-07-19T09:24:07.683
12297
12297
question
swift
Swiftの { }内の処理の流れが分かりません。


メソッド呼び出しの後ろについている `{ ... }` は クロージャ (Closure) と呼ばれるものです。  
`signIn(withEmail:link:)` だけではなく、 `showSpinner` や `hideSpinner` にくっついている `{
... }` もクロージャです。

クロージャは関数のようなものですが、クロージャ自体を変数に入れたり、他のメソッドや関数に渡したり、戻り値として返したりすることができます。

簡単な例を上げると以下のようになります

[code]

    // "ABC"をプリントするクロージャ
    let c1 = {
        print("ABC")
    }
    c1() // ABC と表示される
    
    // 与えられた整数を2倍にするクロージャ
    let c2 = {
        (a:Int) -> Int in
        return a * 2
    }
    c2(2) // 4が返される
    
    // クロージャを引数に受け取る関数
    // 与えられたクロージャを二回呼び出す
    func f1(closure: ()->Void) {
        closure()
        closure()
    }
    
    // "ABC"が二回プリントされる
    f1(closure: c1)
    
    // 関数の最後の引数がクロージャの場合、関数の後ろに { } をくっつけて書くことができる
    f1 {
        print("Yeah!")
    }
    
[/code]

これを踏まえると

> self.hideSpinner{}は必ず実行されるのしょうか？

は **`signIn(withEmail:link:)` の実装や処理結果による**

が回答になります。  
メソッド名からは、サインインが成功したら `user`、失敗したら `error`
に値を入れて、クロージャが呼び出されるのではないかと期待しますが、本当にそうかは分かりません。  
(実装やAPI仕様を確認したり、実際に実行して試してみたりすれば分かるでしょう)

**追記**

forestさんの過去の質問から、おそらくSwiftよりJavaScriptの方が詳しいのかと思います。  
なので元のプログラムをJavaScript風に翻訳してみましょう。以下のようになります。

[code]

    this.showSpinner(function() {
        // [START signin_emaillink]
        Auth.auth().signInWithEmail(email, this.link, function(user, error){
            // [START_EXCLUDE]
            this.hideSpinner( function() {
                if (error) {
                    this.showMessagePrompt(error.localizedDescription);
                    return;
                }
                this.navigationController.popViewControllerAnimated(true);
            });
            // [END_EXCLUDE]
        });
        // [END signin_emaillink]
    });
    
[/code]

つまり、Swiftのクロージャ `{ ... }` はJavaScriptの無名functionと同じでものです。  
無名functionはメソッドの引数として、それぞれ `showSpinner`, `hideSpinner`, `signIn`
という別のメソッドに渡されていることも分かると思います。渡されたfunctionをどう扱うかはそれぞれのメソッドによります。


CC BY-SA 4.0
2019-07-19T07:44:08.763
56745
2019-07-23T03:26:58.967
2019-07-23T03:26:58.967
23829
23829
56742
answer


> `signIn(withEmail:link:)`メソッドの`{}`内の処理の流れがよく分かりません。

`{}`は、クロージャ（Closure）です。まったく実用面で意味のないクロージャですが、わかりやすさ優先で例を出すと、

[code]

    let plus = { (a: Int, b: Int) -> Int in
        return a + b
    }
    
[/code]

`(a: Int, b: Int)`が引数部分、`->
Int`が返り値を表し、`in`以下がクロージャの実装部分です。すなわち、関数と同じ構造になっており、ほぼ関数と同じ働きをします。関数でなくクロージャを使う利点は、例のように、クロージャを変数に代入できることです。上のコードに続いて、

[code]

    let c = plus(a: 4, b: 3) // c = 7
    
[/code]

と書いて、クロージャを実行できます。まんま関数ですね。クロージャと関数の違いは、主にその永続性にあります。関数（独立関数）は、グローバルで、プログラムと同じ寿命を持ち、クラスのメンバーである関数、すなわちメソッドは、インスタンスと同じ寿命になります。対して、クロージャは、一般の値型変数と同じく、コードブロック（`{`から`}`まで）がその寿命になります。  
クロージャは、ほかの言語で「ラムダ式」、「無名関数」などと呼ばれていますので、Swiftから離れて、少しネットで調べてみるといいでしょう。

* * *

クロージャは変数に代入できますから、関数の引数になります。クロージャを引数にとる関数の例を示します。

[code]

    func hoge(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
        return operation(a, b)
    }
    
[/code]

クロージャを代入した変数にも型があり、それは`(Int, Int) -> Int`のような表記になります。

[code]

    let m = hoge(a: 3, b: 4, operation: plus) // m = 7
    
[/code]

クロージャ型の引数は、直接クロージャの実装を記述することができます。

[code]

    let n = hoge(a: 8, b: 3, operation: { (a, b) -> Int in
        return a - b
    })
    // n = 5
    
[/code]

ここまではよろしいでしょうか？  
クロージャを引数にとる関数に対して、Swiftは特別な構文を認めています。クロージャ型の引数が最後尾にあるという条件で、クロージャを`()`の外に出すことができます。上のコードは、このように書き換えできます。

[code]

    let n = hoge(a: 8, b: 3) { (a, b) -> Int in
        return a - b
    }
    
[/code]

クロージャの実装が長くなると、関数の最後、`})`が何のことなのか、すぐに判断できにくくなります。そういう判断のしにくさを緩和する意図だと思われます。

* * *

> このような構文は何と呼ばれるものですか？

ここまでくると、この疑問に答えを出すことができますね。すなわち、クロージャを引数にとるメソッドです。  
あともうすこしです。（ここで全て疑問が解けているなら、これ以上読んでいただかなくてもけっこうです）  
ではつぎの二つのケースを考えてみましょう。ひとつは、関数の引数がクロージャ型一つだけ取るケース。もうひとつは、引数も返り値もないクロージャというケース。この二つのケースを満たすサンプルはこうなります。

[code]

    func fuga(doThis: () -> ()) {
        doThis()
    }
    
[/code]

引数も返り値もないクロージャの型は、`() -> Void`ないし`() -> ()`と書きます。後者が推奨されているようです。  
この関数を実行するには、こう書きます。

[code]

    fuga(doThis: { () -> () in
        print("Hello")
    })
    // 出力 Hello
    
[/code]

（関数の書き方と同じく、返り値のないクロージャは、`return`行を書きません）  
これを省略した構文で書くと、まずクロージャ型の引数は`()`の外に出され、かつ`()`は記述不用となります。そして、クロージャの引数と返り値の型は省略され、`in`も不用となります。

[code]

    fuga {
        print("Hello")
    }
    
[/code]

これで、`self.hideSpinner{}`の謎が解決しました。お疲れ様でした。


CC BY-SA 4.0
2019-07-20T11:57:18.023
56776
2019-07-21T07:15:36.327
2019-07-21T07:15:36.327
18540
18540
56742
answer