Swift'te Escaping ve Non-Escaping

Swift Jul 22, 2023

Swift'te closure, bir işlev veya metot gibi davranabilen bir referans türüdür. Bir closure, içinde tanımlandığı fonksiyondan veya metodan dışarı çıkıp daha sonra başka bir yerde kullanılmak üzere saklanabilir. Bu durumda, escapes olduğu anlamına gelmektedir.  Ancak başka bir yerde kullanılmayacaksa da non-escaping olarak kabul edilir.

Non-Escaping Closure

Bir closure, bir fonksiyonun parametresi olarak yazıldığında ve o fonksiyon tarafından doğrudan çağrıldığında, o closure non-escaping olarak kabul edilir. Bu durumda, closure, fonksiyonun çağırılması sırasında bellekte saklanmaz. Bu nedenle, non-escaping closure'lar için herhangi bir @escaping ön eki kullanmanız gerekmez.

Aşağıdaki örnekte, bir closure bir fonksiyonun parametresi olarak yazılır, ancak doğrudan çağrılır. Bu durumda, closure bir non-escaping closure olarak kabul edilir:


func processNumbers(_ numbers: [Int], closure: (Int) -> Void) {
    for number in numbers {
        closure(number)
    }
}

processNumbers([1, 2, 3]) { number in
    print(number)
}

// 1
// 2
// 3

Escaping Closure

Bir closure, bir fonksiyonun içinde tanımlanır ve daha sonra başka bir yerde çağrılacaksa, o closure escaping bir closure olarak kabul edilir. Bu durumda, closure, fonksiyonun yürütülmesi bittikten sonra bile bellekte saklanır. Bu nedenle, bir escaping closure için, closure'un ne kadar süreyle saklanabileceğini belirleyen @escaping ön eki kullanmanız gerekir.

Aşağıdaki örnekte, bir escaping closure örneği verilmiştir:


func processNumbers(_ numbers: [Int], closure: @escaping (Int) -> Void) {
    DispatchQueue.main.async {
        for number in numbers {
            closure(number)
        }
    }
}

processNumbers([1, 2, 3]) { number in
    print(number)
}

// 1
// 2
// 3

Burada, processNumbers fonksiyonu içinde DispatchQueue.main.async kullanarak bir arka plan iş olarak gönderilmiş bir closure oluşturuyoruz. Bu, fonksiyonun hemen sona ermesine rağmen, gönderilen closure'ın henüz tamamlanmamış olabileceği anlamına gelir.

Bu durumda, gönderilen closure escaping bir closure olduğundan, @escaping ön ekini kullanarak belirtmemiz gerekir. Bu sayede closure bellekte saklanacak ve sonraki bir zaman diliminde çağrılabilir hale gelecektir.

processNumbers fonksiyonu bu şekilde kullanıldığında, gönderilen closure hala tamamlanmamış olsa bile, arka planda bir iş parçacığı kullanarak her sayıyı sırayla işleyecektir.

Daha sık karşılaşılacak bir örnek vermek gerekirse:


func fetchData(completionHandler: @escaping ([String]) -> Void) {
    // API isteği yapılır
    // Yanıt alındıktan sonra closure çağrılır
    let responseData = ["Apple", "Banana", "Cherry"]
    completionHandler(responseData)
}

fetchData { responseData in
    print(responseData)
}

Kaynaklar

The Swift Programming Language: Redirect
Advanced coordinators in iOS
Child coordinators, navigating backwards, passing data between view controllers, and more.

Tags

Furkan Ozoglu

iOS Developer & Geomatics Engineer