エンクロージャ


エンクロージャ

  • SWIFTで関数型プログラミングモードに接触する場合、第1ステップで理解しなければならない概念.
  • エンクロージャは、一定の機能を有するコードを1つのブロックに統合し、
  • .
  • 関数はモジュールの形式です.
  • エンクロージャは、変数または定数を宣言する場所で取得(参照)して保存できます.
  • シャーシの3つの形式
  • 名を有するが値を取得しないグローバル関数の形式
  • の名称を有する、他の関数で値を得ることができるネストされた関数の形式
  • .
  • には名前がなく、周囲のコンテキストに基づいて値を取得できるサムネイル構文形式
  • がある.
  • シャーシの唐雅な表現
  • エンクロージャは、コンテキストからパラメータと戻り値のタイプを推定することができるので、パラメータと戻り値のタイプ
  • を省略することができる.
  • のエンクロージャが1行の表現しかない場合、暗黙的に戻り値(returnキーワードは省略可能)
  • と見なす.
  • 簡略化された伝達パラメータ名
  • を用いる.
  • 以降の行Closer構文は
  • で使用できます.

    きほんキャビネット

  • ソート(:)メソッドを使用して理解します.
  • SWIFT標準ライブラリは、アレイ内の値をソートするために提供されます.
  • は、既存の配列を変更することなく、新しい配列を返します.
  • public func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element]
    
    //정렬할 이름 배열
    let names: [String] = ["wizplan", "eric", "yagom", "jenny"]
  • モジュールではなく関数を使用してnamesをソートします.
  • func backwards(first: String, second: String) -> Bool {
        return first > second
    }
    
    //MARK: 매개변수로써의 함수
    let reversed: [String] = names.sorted(by: backwards)
    
    //MARK: 매개변수에 클로저 대입
    let reversed = names.sorted(by: {(first: String, second: String) -> Bool in
       return  first > second
    })

    後続エンクロージャ

  • 関数または方法の最後の伝達パラメータであるモジュールは、関数または方法の括弧を閉じた後に記述することができる.
  • エンクロージャがやや長い場合や毒性がやや悪い場合は、後続のエンクロージャ機能を使用することができます.
  • しかし、後続モジュールは、最後の伝達パラメータとして伝達されるモジュールにのみ適用されるため、複数の伝達パラメータを伝達するモジュールの場合、後続モジュールとして使用できるのは最後のモジュールのみである.
  • ソート(:)メソッドのように1つのモジュールのみを伝達パラメータとして伝達する場合は、カッコを省略できます.
  • パラメータに複数のエンクロージャがある場合は、後続のエンクロージャ構文を複数使用できます.
  • の複数の後続エンクロージャが使用されている場合、エンクロージャは括弧で開閉され、最初のエンクロージャの伝達パラメータラベルは無視されます.
  • //MARK: 후행 클로저 사용
    let reversed = names.sorted() { (first: String, second: String) -> Bool in
       return  first > second
    }
    
    //MARK: 후행 클로저 사용 - sorted(by:) 메소드의 소괄호까지 생략 가능
    let reversed = names.sorted { (first: String, second: String) -> Bool in
       return  first > second
    }
    
    func doSomething(do: (String) -> Void, 
    								 onSuccess: (Any) -> Void,
    								 onFailure: (Error) -> Void) { 
    			// do something...
    }
    
    //MARK: 다중 후행 클로저의 사용
    doSomething { (something: String) in 
    		//do closure
    } onSuccess: { (result: Any) in
    		//success closure
    } onFailure: { (error: Error) in 
    		//failure closure
    }

    モジュール表示の簡略化

  • コンテキストのタイプ類推を使用
  • メソッドの伝達因子であるモジュールは、メソッド要件の形で伝達されなければならないが、異なることに、伝達因子であるモジュールは適切なタイプを遵守していると推定できる.
  • したがって、
  • は、パラメータを伝達するエンクロージャを実施する際に、明示的に示すことなく、パラメータタイプまたは戻り値のタイプを省略することができる.
  • ショートカット・パラメータ名
  • $0, $1, ... 正味$と数字の組み合わせ
  • のショートカットパラメータ表現を使用する場合、キーワードinを使用してパラメータと戻りタイプ、および実行コードを区別する必要はありません.
  • 暗黙的な戻り表現
  • 戻り値が1行のみモジュール内で実行される場合、その実行文を暗黙的に戻り値として使用することができるため、戻りキーワードを省略することができる.
  • 演算子関数
    演算子関数は、
  • エンクロージャビットに適用できます.
  • //MARK: 문맥 타입유추
    let reversed = names.sorted { (first, second) -> Bool in
       return  first > second
    }
    
    //MARK: 단축인자 사용
    let reversed = names.sorted {
        return  $0 > $1
    }
    
    //MARK: 암시적 반환 표현
    let reversed = names.sorted {
        $0 > $1
    }
    
    //MARK: 클로저로서의 연산자 함수 사용
    let reversed = names.sorted(by: >)
    

    取得値

  • エンクロージャは、その定義された位置の周囲コンテキストから定数または変数(capture)を取得することができる.
  • の値を得ることによって、エンクロージャは、周囲に定義された定数または変数が存在しなくても、その定数または変数の値を自身の内部で参照または修正することができる.
  • エンクロージャは、特に非同期操作によく使用されます.エンクロージャによって非同期コールバックが作成され、現在のステータスが事前に取得されない場合、実際にエンクロージャ機能を実行した瞬間に、周囲の定数または変数がメモリに存在しない可能性があります.
  • 重畳関数もエンクロージャであり、重畳関数の周囲の変数または定数を得ることができる.
  • func makeIncrementer(forIncrement amount: Int) -> (() -> Int) {
        var runningTotal = 0
        func incrementer() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementer
    }
    
    let incrementByTwo: (() -> Int) = makeIncrementer(forIncrement: 2)
    
    let first: Int = incrementByTwo()
    let second: Int = incrementByTwo()
    let thrid: Int = incrementByTwo()
    
    print(first)
    print(second)
    print(thrid)
    
    ---result---
    2
    4
    6
  • 増分()関数の周囲にrunningTotalとamount変数があるため、増分()関数は2つの変数の参照を得る.
  • 参照が得られた後、runningTotalおよびamountはmakeIncrementer関数の実行が完了した後も消えず、インクリメンタルを呼び出すたびに使用を継続することができる.
  • 💡 クラスインスタンスハンドラとしてのモジュール
    クラスインスタンスにPropertyエンクロージャを割り当てると、そのインスタンスまたはインスタンスメンバーの参照が得られますが、エンクロージャとインスタンスの間に強いループの問題が発生する可能性があります.

    エンクロージャは参照タイプです

  • 関数およびモジュールは「参照タイプ」であるため、incrementByTwoはrunningTotal値の取得によって増加し続けることができる.
  • 関数またはモジュールが定数または変数に割り当てられるたびに、実際には定数または変数の関数またはモジュールの参照が設定されます.
  • すなわち、定数(incrementByTwoと呼ばれる)にモジュールを割り当てることは、モジュールに参照を割り当てることであり、モジュールに値を割り当てることではない.
  • 最終的にモジュールの参照が別の定数に割り当てられると、両方の定数が同じモジュールを指していることを示します.

    ディスタンス

  • 関数の伝達因子として、伝達されたモジュールが関数終了後に呼び出されると、モジュール関数は탈출(Escape)として表される.
  • エンクロージャをパラメータとする関数を宣言すると、パラメータ名のコロン(:)の後に@escapingキーワードを使用してエンクロージャから飛び出すことを許可することを明記できます.
  • 非同期動作を実行する関数は、コンパイルハンドル伝達パラメータとしてモジュールを受信し、非同期動作が関数を終了した後、呼び出す必要があるモジュールを使用する必要がある場合は、ポップアップモジュール(Escaping Close)を使用する必要があります.
  • exapeキーワード
  • @exapeがない場合は、非exape closure(Nonescape Close)として扱うことができ、関数として渡されるclose関数の動作が完了してから使用する必要がない場合は非exape closeを使用します.
  • モジュールが離脱できる場合
  • 関数の外部で定義された変数または定数に格納され、関数が終了した後に使用されます.
  • 関数の伝達パラメータで伝達されたエンクロージャが戻る(戻る)場合、
  • となる.
    typealias VoidVoidClosure = () -> ()
    let firstClosure: VoidVoidClosure = {
        print("Closure A")
    }
    
    let secondClosure: VoidVoidClosure = {
        print("Closure B")
    }
    //first, second 매개변수 클로전느 함수의 반환 값으로 사용될 수 있으므로 탈출 클로저.
    func returnOneClosure(first: @escaping VoidVoidClosure, second: @escaping VoidVoidClosure, shouldReturnFirstClosure: Bool) -> VoidVoidClosure {
        return shouldReturnFirstClosure ? first : second
    }
    
    //함수에서 반환한 클로저가 함수 외부의 상수에 저장됨.
    let returnedClosure: VoidVoidClosure = returnOneClosure(first: firstClosure, second: secondClosure, shouldReturnFirstClosure: true)
    
    returnedClosure()
    
    var closures: [VoidVoidClosure] = []
    
    //closure 매개변수 클로저는 함수 외부의 변수에 저장될 수 있으므로 탈출 클로저.
    func appendClosure(closure: @escaping VoidVoidClosure) {
        closures.append(closure)
    }
  • タイプの内部メソッドのパラメータモジュールで@experitキーワードが使用されている場合、モジュール内でこのタイプのproperty、メソッド、サブスクリプトにアクセスするには、selfキーワードを明確に使用する必要があります.
  • 非ポップアップキャビネットは、キャビネット内部でタイプ内部のPropertyやMethod、Subscriptなどにアクセスする場合、selfキーワードを必ずしも使用する必要はありません.(オプション)
  • func functionWithNoescapeClosure(closure: VoidVoidClosure) {
        closure()
    }
    
    func functionWithEscapingClosure(completionHandler: @escaping VoidVoidClosure) -> VoidVoidClosure {
        return completionHandler
    }
    
    class SomeClass {
        var x = 10
        func runNoescapeClosure() {
            functionWithNoescapeClosure { x = 200}
        }
    
        func runEscapingClosure() -> VoidVoidCLosure {
            return functionWithEscapingClosure { self.x = 100}
        }
    }
    
    let instance = SomeClass()
    instance.runNoescapeClosure()
    print(instance.x) // 200
    
    let returnedClosure: VoidVoidClosure = instance.runEscapingClosure()
    returnedClosure()
    print(instance.x) // 100