[Swift🦩] #7キャビネット


  • コードで提供される周辺機能ブロック.inline function
  • CのblockやPythonのramdaに似ています.
  • で定義されたコンテキストで、すべての定数および変数への参照をキャプチャして保存できます->これらの定数と変数をオフと呼び、キャプチャされた定数と変数のメモリ管理が自動的に完了します.
  • メモリ管理のため、弱いselfを使用しています.
    タイプ名グローバル関数OXネスト関数Oキャプチャ可能なモジュール式X周囲コンテキストのO
    ->Closer式を使用すると、簡潔な構文を使用できます.

    1.モジュール式


    例は、ソートされたことを示します(by:).
    他の言語と同様に、ソート時に前後の2つのパラメータを比較し、Bool値(最初の値の前がtrue、2番目の値の前がfalse)を返すモジュールを入れます.
    let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

    1.関数として渡す

    func backward(_ s1: String, _ s2: String) -> Bool {
        return s1 > s2
    }
    var reversedNames = names.sorted(by: backward)
    // reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

    2.キャビネットの使用


    RxSWIFTを返す視認性のような複雑なモジュールではreturn typeを指定する必要がある.
    reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
        return s1 > s2
    })
    
    // 타입 유추
    reversedNames = names.sorted(by: { s1, s2 in
        return s1 > s2
    })
    
    // 암시적 반환
    reversedNames = names.sorted(by: { s1, s2 in 
        s1 > s2 
    })
    
    // 짧은 인자 이름
    reversedNames = names.sorted(by: { $0 > $1 } )
    
    // 연산자 메서드 : 이건 연산자인 경우.
    reversedNames = names.sorted(by: >)

    3.後続モジュール

  • 関数のパラメータが1つのモジュールしかない場合は、カッコを省略できます.
  • reversedNames = names.sorted { $0 > $1 }
    もし前に
  • モジュールでないパラメータがあったら?
  • loadPicture(from: someServer) { picture in
        someView.currentPicture = picture
    }
  • のキャビネットパラメータが複数ある場合は?
  • loadPicture(from: someServer) { picture in
        someView.currentPicture = picture
    } onFailure: {
        print("Couldn't download the next picture.")
    }

    2.値を取る

  • エンクロージャは、周囲の環境で定数および変数
  • を取得できます.
  • ==元の範囲が存在しなくても、定数、変数を参照して変更できます.
  • 取得例-ネスト関数
  • runningTotalがキャプチャされ、runningTotalを参照して変更されるため、runningTotalの値自体が変更されます.
  • func makeIncrementer(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementer() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementer
    }
    
    let incrementByTen = makeIncrementer(forIncrement: 10)
    
    incrementByTen()
    // returns a value of 10
    incrementByTen()
    // returns a value of 20
    incrementByTen()
    // returns a value of 30
    
    // 새로운 참조에 저쟝된다.
    let incrementBySeven = makeIncrementer(forIncrement: 7)
    incrementBySeven()
    // returns a value of 7

    3.参照タイプ

  • に割り当てられた関数のrunningTotalが増加し続ける理由は、モジュールが参照タイプであるためである.
  • したがって、
  • は、新しい変数に同じモジュールを割り当てると、同じモジュールを参照し、同じrunningTotalを参照します.
  • let alsoIncrementByTen = incrementByTen
    alsoIncrementByTen()
    // returns a value of 50
    
    incrementByTen()
    // returns a value of 60

    4. escape closure ⭐️⭐️

  • 関数を返して呼び出されたエンクロージャ.
  • 非同期で実行する必要がある
  • タスクについては、
    関数は完了しましたが、通常は非同期でデータを受信するタスクは完了しません.
  • したがって、
  • は、データを受信して処理すると、使用のために関数にモジュールを送信する、
  • .
  • のような関数が終了して動作するモジュールでは,@逃走というキーワードを書くべきである.
  • 脱出clousureでselfを使用する場合は、ループリファレンスに注意してください.
  • は、エスケープキャビネットを使用する場合にselfを明示的に使用する必要があるためである.
  • var completionHandlers: [() -> Void] = []
    func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
        completionHandlers.append(completionHandler)
    }
    
    func someFunctionWithNonescapingClosure(closure: () -> Void) {
        closure()
    }
    
    class SomeClass {
        var x = 10
        func doSomething() {
            someFunctionWithEscapingClosure { self.x = 100 }
            // someFunctionWithEscapingClosure { [self] in x = 100 }
            someFunctionWithNonescapingClosure { x = 200 }
        }
    }
    
    let instance = SomeClass()
    instance.doSomething()
    print(instance.x)
    // Prints "200"
    
    completionHandlers.first?()
    print(instance.x)
    // Prints "100"

    5. auto closure


    自動生成されたモジュールは、パラメータとして
  • 関数に渡される式をカプセル化するために使用される.
  • パラメータがなく、戻り値のみの式をcloserに自動的に変換します.
  • を開発する過程で、直接実現することは多くない.
  • 次のモジュールの関数でパラメータを渡す場合は、パッケージ化して{}に送信します.もちろんです.Closerim
    // customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
    func serve(customer customerProvider: () -> String) {
        print("Now serving \(customerProvider())!")
    }
    serve(customer: { customersInLine.remove(at: 0) } )
    // Prints "Now serving Alex!"
    ただし、auto closureキーワードとして入れると、渡された式がcloserでなくても自動的にclosureに変換されて実行されます.
    // customersInLine is ["Ewa", "Barry", "Daniella"]
    func serve(customer customerProvider: @autoclosure () -> String) {
        print("Now serving \(customerProvider())!")
    }
    serve(customer: customersInLine.remove(at: 0))
    // Prints "Now serving Ewa!"
    serve(customer: "hello")
    // Prints "Now serving hello!"
    Autoclosureは、closureを脱出する可能性もあります.
    auto closure活用例はこちらで参考にしてみてください!
    https://jusung.github.io/AutoClosure/

    n.問題


    脱出室を説明してください。


    脱出室は脱出室です.closureは、モジュールが関数の外部ではなく関数の内部で使用されている場合、関数のサムネイルと見なすことができます.(特に、非同期操作を実行する場合、関数の終了後に実行を続行するコードがある場合).関数の外部で後で使用するcloser.パラメータラベルの前に@experitキーワードを使用してタグを付けます.
    +)追加で探したもの.
  • エンクロージャのデフォルト値は、パフォーマンスを向上させるために非脱出コンパイラコードを最適化することです.
    必ず
  • selfと明記してください->メモリを管理するには、弱いselfを使用するかどうかを考慮する必要があります.
  • リファレンス
    https://bbiguduk.gitbook.io/swift/language-guide-1/closures
    https://github.com/JeaSungLEE/iOSInterviewquestions