Domknięcia
Domknięcia
Domknięcia to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 1 z 1. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Swift Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Swift Academy zawiera 1 lekcji w sumie.
Wprowadzenie
Dzień dobry,
Domknięcia to samodzielne bloki kodu. Domknięcie można przekazać do funkcji jako parametr albo użyć wewnątrz kodu.
Domknięcie to rodzaj funkcji. Można je przekazywać w kodzie. Są podobne do lambd w innych językach programowania.
Zarządzanie pamięcią
Jedną z najważniejszych kwestii jest to, że domknięcie może przechowywać wartości stałych i zmiennych z kontekstu, w którym zostało zdefiniowane.
Zjawisko to nazywa się przechwytywaniem (closing-over).
Swift zarządza pamięcią podczas tego przechwytywania.
Typy domknięć
Istnieją różne typy domknięć.
- Funkcje globalne to nazwane domknięcia. Funkcje te nie przechowują żadnych wartości.
- Funkcje zagnieżdżone mogą przechowywać wartości z otaczającej je funkcji.
- Wyrażenie domknięcia jest natomiast anonimowym domknięciem i za pomocą prostej składni może przechowywać dane z otaczającego je kontekstu.
Składnia domknięć
Składnię domknięć upraszczano tak bardzo, jak to możliwe. Najważniejsze elementy są następujące.
- Parametry w domknięciach mogą być wywnioskowane.
- Można wywnioskować wartości zwracane.
- Zwracanie z domknięcia może odbywać się w jednym wierszu.
- Nazwy argumentów można wyrażać za pomocą skrótów, takich jak $ 0 lub $ 1.
- Można używać składni trailing closure.
Informacja
Wyrażenia domknięć oznaczają zapisywanie domknięć bezpośrednio w kodzie, z naciskiem na składnię i prostotę.
Składnia domknięcia
Przykładową składnię domknięcia przedstawiono w poniższym kodzie.
{ (parameters) -> return type in
statements
}
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
//If we didn't use closures, our code structure would be as follows.
var reversedNames = names.sorted(by: backward)
Składnia domknięcia
Jednak w przypadku domknięcia nie musimy definiować niepotrzebnie nazwanego globalnego domknięcia tego typu.
Wystarczy zdefiniować proste wyrażenie domknięcia jako parametr. Przyjrzyjmy się przykładowi.
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
print(reversedNames)
///sorted method takes closure as parameter.Słowo kluczowe in
Na podstawie słowa kluczowego in można zrozumieć, że zaczyna się treść domknięcia.
Przed słowem kluczowym in należy zdefiniować parametry przekazywane do domknięcia oraz typ zwracany.
Wnioskowanie typu na podstawie kontekstu
Wnioskowanie typów na podstawie kontekstu
W powyższym przykładzie można wywnioskować parametry i typ zwracany wyrażenia domknięcia, ponieważ metoda sorted przyjmuje domknięcie.
Nie musimy więc definiować ich dodatkowo.
W tym przykładzie, ponieważ wartości w tablicy names są typu String, parametry przyjmowane przez domknięcie również będą typu String.
Podobnie odpowiednie domknięcie musi zwracać wartość typu Bool, aby posortować elementy, więc typ zwracany zostanie wywnioskowany jako Bool.
Przykład
Upraszcza to poniższy zapis.
Strzałkę można również pominąć w kodzie, wnioskując typ zwracany.
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
print(reversedNames)Skrócona składnia
Zamiast skróconej składni lepiej używać pełnej składni, aby nie wprowadzać czytelników kodu w błąd.
Powyższą składnię można jeszcze bardziej skrócić.
Zwracaną wartość można skrócić w wyrażeniu domknięcia, usuwając słowo kluczowe return.
/*
In this example, the return keyword has been extracted.
It already has single expression.
There is no need to express it as an extra with return.
*/
var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
print(reversedNames)Przykład
W tym przykładzie pominięto słowo kluczowe return.
Mamy już tylko jedno wyrażenie, więc nie ma potrzeby dodatkowo poprzedzać go słowem return.
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )Skrócone nazwy parametrów
Składnię można jeszcze bardziej skrócić. W powyższym przykładzie stwierdziliśmy, że domknięcie przyjmuje dwa parametry (w tym s1 i s2). Ich typy są wywnioskowane.
Teraz możemy uniknąć kłopotu z zapisywaniem tych parametrów i definiowaniem ich typów, korzystając ze skrótów.
Ponadto, ponieważ nie definiujemy parametrów ani nie przekazujemy wartości zwracanej, można również pominąć słowo kluczowe in.
let names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { $0 > $1 } )
print(reversedNames)
// In this example $0 will shortcut the first parameter and $1 will shortcut the second parameter.Skrócenie przykładu
var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: >)
print(reversedNames)
// Greater than operator takes two parameters and the rotation type is squat.TRAILING CLOSURE
Trailing Closure
Jeśli parametr przekazywany do funkcji jest domknięciem, znajduje się na końcu listy argumentów, a wyrażenie domknięcia jest długie, wygodniej może być zapisanie go jako trailing closure.
Trailing closure to cukier składniowy, który zwiększa czytelność kodu.
Parametrem końcowym większości metod iOS jest domknięcie.
Parametr końcowy
Na przykład w tym przypadku ostatnim parametrem jest domknięcie.
class Animator {
class func animate(withDuration duration: Double, animations: () -> Void) {
animations()
}
}
class MyViewController {
func start() {
// With the traditional method, we can call this fund as follows.
Animator.animate(withDuration: 1, animations: { [unowned self] in
print("red")
})
}
}
MyViewController().start()Ponieważ powyższy kod jest mniej czytelny, można go zapisać następująco
Ponieważ powyższy kod jest mniej czytelny, można go zapisać następująco.
import Foundation
Thread.sleep(forTimeInterval: 1)
print("Background color changed to red")Przykład
Podczas korzystania ze składni trailing closure nie musimy zapisywać etykiety argumentu.
Ponieważ domknięcie jest teraz częścią wywołania funkcji.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}Składnia
Składnię trailing closure można w rzeczywistości traktować jako cukier składniowy. Zwiększa ona czytelność kodu.
/*
In the example below, animations
are expressed as closure.
*/
public class func animate(withDuration: TimeInterval, animations: () -> Void)
// In traditional usage, we need to make a call like the following.
UIView.animate(withDuration: 1, animations: { [unowned self] in
self.view.backgroundColor = UIColor.red
})
/*
In this way, both the readability of the code
increases and we avoid the use of extra brackets.
If it is as above and the last parameter of the method
is closure, Swift allows to make a call like the one below.
*/
UIView.animate(withDuration: 1) { [unowned self] in
self.view.backgroundColor = UIColor.red
}Do przetestowania kodu możemy użyć kodu poniżej
Do przetestowania kodu możemy użyć kodu poniżej.
func greetThenRunClosure(name: String, closure: () -> ()) {
print("Hello, \(name)!")
closure()
}
greetThenRunClosure(name: "Paul") {
print("The closure was run")
}Przechwytywanie wartości przez domknięcia
Przechwytywanie wartości przez domknięcia
Domknięcie może przechowywać wartości zmiennych z otaczającego je środowiska. Można nawet zmieniać wartości tych zmiennych i uzyskiwać do nich dostęp z poziomu treści domknięcia.
Nawet jeśli zmienne te nie znajdują się w pierwotnym zakresie, w którym zostały zdefiniowane.
Ciąg dalszy
Ogólnie rzecz biorąc, dane te mogą być przechowywane przez funkcje zagnieżdżone i wyrażenia domknięć. Mogą one przechowywać dane funkcji zewnętrznej.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen())
// returns a value of 10
print(incrementByTen())
// returns a value of 20
print(incrementByTen())
// returns a value of 30Ciąg dalszy
Jeśli przypiszemy domknięcie jako właściwość klasy, zacznie ono przechowywać silne odwołanie do tej instancji.
W ten sposób między domknięciem a instancją powstanie cykl silnych odwołań.
Należy zwrócić szczególną uwagę na wycieki pamięci.
Uwaga
Domknięcia i funkcje są typami referencyjnymi.
@escaping
Takie użycie może być potrzebne w wielu miejscach, w których domknięcie jest używane asynchronicznie.
W pierwszych wersjach Swift (1 i 2) domknięcia w parametrach były typu escaping, a później stały się domknięciami non-escaping. Jeśli trzeba było przekazać domknięcie jako non-escaping, należało wyraźnie to określić.
W kolejnych wersjach parametry domknięć stały się typu non-escaping, aby zmniejszyć zużycie pamięci.
Obecnie, jeśli chcemy zdefiniować parametr jako escaping, musimy oznaczyć go słowem kluczowym @escaping.
Słowo kluczowe @ESCAPING
Słowo kluczowe @ESCAPING
Jeśli chcemy móc wywoływać domknięcia przekazane do funkcji po jej zakończeniu, musimy oznaczyć parametr słowem kluczowym @escaping.
Domknięcia domyślnie przekazywane do funkcji są typami referencyjnymi, ale nie zwiększają liczby odwołań. Ponieważ po wywołaniu wykonanie takiego domknięcia się kończy, nie musimy dodatkowo zwiększać liczby odwołań.
Jeśli jednak potrzebujemy używać domknięcia przekazanego jako parametr po wywołaniu funkcji, musimy oznaczyć ten parametr słowem kluczowym @escaping.
nonEscaping
Najpierw zobaczmy, jak działa domknięcie nonEscaping.
Gdy takie domknięcie zostanie przekazane do funkcji jako parametr, zostanie wykonane w treści funkcji, a następnie sterowanie wróci do kompilatora.
Po zakończeniu funkcji, czyli po wykonaniu kodu, domknięcie opuszcza swój zakres i pamięć może zostać zwolniona.
Używanie domknięcia escaping
Używanie domknięcia escaping
Po przekazaniu domknięcia do funkcji jako argumentu domknięcie nadal jest przechowywane, nawet po zakończeniu funkcji i wykonaniu kodu.
Zajmuje ono miejsce w pamięci aż do wykonania domknięcia. Istnieje kilka typów domknięć escaping.
Gratulacje
Gratulacje 🎉
Dotarli Państwo do końca tej lekcji.
Do zobaczenia w następnej lekcji 😎

Często zadawane pytania
Czy lekcja „Domknięcia” jest bezpłatna?
Tak — pełny tekst „Domknięcia” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Swift Academy, przejdź na CoddyKit PRO. Kurs Swift Academy zawiera 1 lekcji w sumie.
Co nauczysz się w „Domknięcia”?
Domknięcia Ćwiczysz Swift Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Swift Academy?
Nie wymagamy żadnego doświadczenia. Swift Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 1.
Ile czasu zajmuje lekcja „Domknięcia”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Swift Academy?
Tak. Każda lekcja Swift Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.