Sobes.tech
Junior

Was ist eine Closure?

sobes.tech KI

Antwort von AI

Schließen (Closure) in Swift ist ein eigenständiger Funktionsblock ({}), der im Code übergeben und verwendet werden kann. Schließungen können Referenzen auf Konstanten und Variablen aus dem Kontext erfassen und speichern, in dem sie definiert sind.

Verwendungsbeispiele:

  • Als Argumente von Funktionen (z.B. Completion Handlers).
  • Zur Definition des Verhaltens bei der Enumeration von Sammlungen (z.B. mit Methoden map, filter, reduce, sorted).
  • Für die verzögerte Ausführung von Code.

Syntax:

// Grundlegende Syntax
{ (Parameter) -> Rückgabetyp in
    Anweisungen
}

// Beispiel für eine Closure, die einen Int annimmt und einen String zurückgibt
let integerToString: (Int) -> String = { (number: Int) -> String in
    return "Zahl: \(number)"
}

Eigenschaften:

  • Automatisches Erfassen von Variablen.
  • Möglichkeit, Closures ohne explizite Angabe der Parameter- und Rückgabetypen zu definieren (syntaktischer Zucker).
  • Verwendung verkürzter Namen für Parameter ($0, $1, etc.).
  • Closure-Syntax mit trailing closure.

Variablen erfassen:

Ein Closure kann Variablen aus seiner Umgebung erfassen. Standardmäßig erfolgt die Erfassung per Referenz. Wenn ein Closure nach dem Verlassen des ursprünglichen Gültigkeitsbereichs der Variablen verwendet wird, behält es dennoch Zugriff auf diese.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0 // Variable aus externem Kontext
    let incrementer: () -> Int = { // Closure
        runningTotal += amount // Erfasst runningTotal und amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Ausgabe: 10
print(incrementByTen()) // Ausgabe: 20

Aufnahmelisten (Capture Lists):

Werden verwendet, um explizit anzugeben, wie Variablen erfasst werden sollen – per Wert oder per Referenz – und um starke Referenzzyklen (retain cycles) zu vermeiden.

class MyClass {
    var value = 0

    lazy var myClosure: () -> Void = { [self, value] in // Erfassen von self per Referenz, von value per Wert
        print("Wert von self.value: \(self.value)")
        print("Erfasster Wert: \(value)")
    }

    deinit {
        print("MyClass-Instanz freigegeben")
    }
}

Um starke Referenzzyklen beim Erfassen von Klassenobjekten zu vermeiden, verwendet man die Syntax [weak self] oder [unowned self].

class ViewController {
    var dataFetcher: DataFetcher?

    func fetchData() {
        dataFetcher?.fetch { [weak self] result in // Schwacher Bezug auf self
            guard let self = self else { return } // Überprüfung auf Existenz von self
            // Ergebnisverarbeitung
        }
    }
}

class DataFetcher {
    var completionHandler: ((Result<String, Error>) -> Void)?

    func fetch(completion: @escaping (Result<String, Error>) -> Void) {
        self.completionHandler = completion
        // Asynchrone Operation...
    }
}