Swift'te Escaping ve Non-Escaping
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)
}