0Pricing
Swift Academy · Lekcja

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ęć.

  1. Funkcje globalne to nazwane domknięcia. Funkcje te nie przechowują żadnych wartości.
  2. Funkcje zagnieżdżone mogą przechowywać wartości z otaczającej je funkcji.
  3. 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 30

Cią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 😎

Domknięcia — ilustracja 29

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.

← Powrót do Swift Academy