@dynamicMemberLookup
Budowanie dynamicznego, bezpiecznego typowo dostępu do składowych.
@dynamicMemberLookup to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 4 z 4. 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 4 lekcji w sumie.
Czym jest dynamiczne wyszukiwanie członków
Atrybut @dynamicMemberLookup pozwala typowi reagować na dostęp do członka za pomocą składni kropkowej, nawet jeśli nie zadeklarowano go jako rzeczywistej właściwości. Po zapisaniu value.something Swift przekierowuje ten dostęp do zdefiniowanego przez programistę specjalnego indeksu dolnego.
Dzięki temu typy opakowujące zachowują naturalny sposób użycia, a cała obsługa dostępu pozostaje w jednym miejscu.
@dynamicMemberLookup
struct Settings {
private var storage: [String: String] = ["theme": "dark"]
subscript(dynamicMember key: String) -> String? {
storage[key]
}
}
let s = Settings()
print(s.theme ?? "none")Wymagany indeks dolny
Typ oznaczony @dynamicMemberLookup musi implementować subscript(dynamicMember:). Gdy parametr jest typu String, wpisana nazwa członka staje się w czasie wykonywania tym ciągiem znaków.
Zatem config.timeout wywołuje indeks dolny z kluczem "timeout".
@dynamicMemberLookup
struct Config {
let values: [String: Int]
subscript(dynamicMember member: String) -> Int {
values[member] ?? 0
}
}
let config = Config(values: ["timeout": 30, "retries": 3])
print(config.timeout)
print(config.retries)Wyszukiwanie oparte na String nie jest bezpieczne typowo
Dynamiczne wyszukiwanie członków oparte na ciągach znaków jest elastyczne, ale pozbawia kod sprawdzania w czasie kompilacji. Jeśli nazwa członka zostanie wpisana błędnie, kod nadal się skompiluje, a wynik będzie zależeć od tego, co indeks dolny zwraca dla brakującego klucza.
Poniżej nieznany członek po cichu zwraca wartość domyślną zamiast powodować błąd kompilacji.
@dynamicMemberLookup
struct Config {
let values: [String: Int]
subscript(dynamicMember member: String) -> Int {
values[member] ?? -1
}
}
let config = Config(values: ["timeout": 30])
print(config.tmout)Bezpieczne typowo wyszukiwanie za pomocą ścieżek kluczy
Dla większego bezpieczeństwa można sprawić, aby indeks dolny przyjmował KeyPath zamiast ciągu znaków. Wtedy kompilator sprawdza, czy członek istnieje w opakowywanym typie, przywracając pełną kontrolę typów i jednocześnie przekazując dostęp dalej.
Ten wzorzec doskonale nadaje się do typów opakowujących, które przechowują wartość o silnym typowaniu.
struct User { let name: String; let age: Int }
@dynamicMemberLookup
struct Boxed {
let user: User
subscript<T>(dynamicMember path: KeyPath<User, T>) -> T {
user[keyPath: path]
}
}
let boxed = Boxed(user: User(name: "Ada", age: 36))
print(boxed.name)
print(boxed.age)Dlaczego wersja ze ścieżką klucza jest bezpieczniejsza
Ponieważ indeks dolny przyjmuje KeyPath<User, T>, dozwolone są tylko człony, które rzeczywiście istnieją w User. Literówka taka jak boxed.naem spowodowałaby teraz błąd kompilacji, w przeciwieństwie do wersji opartej na ciągu znaków.
Zyskuje się wygodę składni kropkowej bez związanego z nią ryzyka.
struct User { let name: String; let age: Int }
@dynamicMemberLookup
struct ReadOnly {
let value: User
subscript<T>(dynamicMember path: KeyPath<User, T>) -> T {
value[keyPath: path]
}
}
let r = ReadOnly(value: User(name: "Lin", age: 22))
print(r.name, r.age)Zapisywalne człony dynamiczne
Jeśli indeks dolny udostępnia setter i przyjmuje WritableKeyPath, można również przypisywać wartości do przekazywanych członów. Typ opakowujący przekazuje zapis bezpośrednio do opakowywanej wartości.
Dzięki temu powstaje przezroczysty, zmienny typ opakowujący.
struct Profile { var name: String; var score: Int }
@dynamicMemberLookup
struct Wrapper {
var value: Profile
subscript<T>(dynamicMember path: WritableKeyPath<Profile, T>) -> T {
get { value[keyPath: path] }
set { value[keyPath: path] = newValue }
}
}
var w = Wrapper(value: Profile(name: "Mo", score: 0))
w.score = 99
print(w.value.score)Przekazywanie dostępu do opakowanego obiektu
Dynamiczne wyszukiwanie członków doskonale nadaje się do lekkich proxy, które głównie przekazują dostęp do wewnętrznej wartości, ale dodają niewielką porcję logiki. Indeks dolny skupia logikę przekazywania w jednym miejscu.
Tutaj opakowanie rejestrujące przekazuje odczyty i wypisuje, do którego członka uzyskano dostęp.
struct Account { let id: Int; let balance: Double }
@dynamicMemberLookup
struct Logged {
let account: Account
subscript<T>(dynamicMember path: KeyPath<Account, T>) -> T {
let result = account[keyPath: path]
print("accessed a member")
return result
}
}
let logged = Logged(account: Account(id: 7, balance: 100))
print(logged.balance)Łączenie z koncepcjami dynamicznych wywołań
Dynamiczne wyszukiwanie członków dobrze współpracuje z generycznością. Pojedynczy generyczny indeks dolny może przekazywać właściwości dowolnego typu, dlatego jedno opakowanie obsługuje wartości o różnych strukturach.
Tutaj ten sam typ Proxy działa zarówno wtedy, gdy członek jest typu String, jak i wtedy, gdy jest typu Int.
struct Item { let title: String; let count: Int }
@dynamicMemberLookup
struct Proxy<Wrapped> {
let wrapped: Wrapped
subscript<T>(dynamicMember path: KeyPath<Wrapped, T>) -> T {
wrapped[keyPath: path]
}
}
let proxy = Proxy(wrapped: Item(title: "Book", count: 4))
print(proxy.title, proxy.count)Wyszukiwanie oparte na String dla danych podobnych do JSON
Wersja oparta na ciągach znaków nadal ma swoje zastosowanie: służy do reprezentowania luźno ustrukturyzowanych danych, takich jak przeanalizowany JSON, gdy członkowie nie są znani w czasie kompilacji. Każdy dostęp staje się wyszukiwaniem w słowniku.
Tutaj niewielka wartość podobna do JSON udostępnia swoje pola za pomocą składni kropkowej.
@dynamicMemberLookup
struct JSON {
let fields: [String: String]
subscript(dynamicMember key: String) -> String {
fields[key] ?? ""
}
}
let json = JSON(fields: ["city": "Oslo", "country": "Norway"])
print(json.city)
print(json.country)Ograniczenia, o których należy pamiętać
Dynamiczne wyszukiwanie członków wpływa tylko na składnię dostępu do członków — nie dodaje rzeczywistych przechowywanych właściwości. Narzędzia takie jak autouzupełnianie działają w przypadku wersji ze ścieżką klucza, ale nie w przypadku dowolnych kluczy będących ciągami znaków.
Wersję ze ścieżką klucza należy preferować, gdy struktura bazowa jest znana, a wersję opartą na ciągach znaków rezerwować dla rzeczywiście dynamicznych danych.
struct Point { let x: Int; let y: Int }
@dynamicMemberLookup
struct Safe {
let point: Point
subscript<T>(dynamicMember path: KeyPath<Point, T>) -> T {
point[keyPath: path]
}
}
let safe = Safe(point: Point(x: 3, y: 4))
print(safe.x + safe.y)Praktyczny dekorator
Łącząc wszystkie elementy, otrzymujemy tutaj wyważone opakowanie, które przekazuje każdy odczyt właściwości do swojej wewnętrznej wartości, jednocześnie zliczając odwołania. Rzeczywiste frameworki wykorzystują ten pomysł do obserwacji i śledzenia.
Składnia kropkowa opakowania jest praktycznie identyczna z bezpośrednim użyciem wartości.
struct Sensor { let temperature: Double; let humidity: Double }
@dynamicMemberLookup
class Tracked {
let sensor: Sensor
var reads = 0
init(_ s: Sensor) { sensor = s }
subscript<T>(dynamicMember path: KeyPath<Sensor, T>) -> T {
reads += 1
return sensor[keyPath: path]
}
}
let t = Tracked(Sensor(temperature: 21.5, humidity: 0.4))
print(t.temperature)
print(t.humidity)
print(t.reads)Szybkie sprawdzenie: bezpieczne typowo dynamiczne wyszukiwanie
Przypomnij sobie, który parametr indeksu dolnego zapewnia bezpieczeństwo typów w dynamicznym wyszukiwaniu członków.
Podsumowanie: dynamiczne wyszukiwanie członków
W tej lekcji poznano działanie @dynamicMemberLookup:
- Atrybut kieruje niezadeklarowany dostęp z użyciem składni kropkowej do
subscript(dynamicMember:). - Parametr
Stringzapewnia elastyczny, ale pozbawiony kontroli typów dostęp, idealny do danych przypominających JSON. - Parametr
KeyPathprzywraca pełne bezpieczeństwo typów i autouzupełnianie. WritableKeyPathz setterem pozwala przekazywać zapisy przez wrapper.- Jest to udogodnienie składniowe, które naturalnie łączy się ze wzorcami proxy i dekoratora.
Ma się teraz do dyspozycji pełny zestaw narzędzi ścieżek kluczowych: odczytywanie, zapisywanie, użycie w kolekcjach i dynamiczne przekazywanie.
struct User { let name: String }
@dynamicMemberLookup
struct Wrap {
let user: User
subscript<T>(dynamicMember path: KeyPath<User, T>) -> T {
user[keyPath: path]
}
}
print(Wrap(user: User(name: "Final")).name)Ucz się Swift dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 122
- Lekcje
- 409
Często zadawane pytania
Czy lekcja „@dynamicMemberLookup” jest bezpłatna?
Tak — pełny tekst „@dynamicMemberLookup” 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 4 lekcji w sumie.
Co nauczysz się w „@dynamicMemberLookup”?
Budowanie dynamicznego, bezpiecznego typowo dostępu do składowych. Ć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 4 z 4.
Ile czasu zajmuje lekcja „@dynamicMemberLookup”?
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.
Wszystkie lekcje w tym kursie
- Podstawy KeyPath
- Używanie KeyPath w kolekcjach
- Zapisywalne i referencyjne KeyPath
- @dynamicMemberLookup