# Top 25 pytań rekrutacyjnych ze Swift dla programistów iOS > Przygotowanie do rozmów rekrutacyjnych na stanowisko iOS: 25 najczęściej zadawanych pytań ze Swift dotyczących optionali, closures, ARC, protokołów, async/await i zaawansowanych wzorców. - Published: 2026-01-29 - Updated: 2026-04-12 - Author: SharpSkill - Tags: swift, ios, interview, career, apple - Reading time: 15 min --- Rozmowy kwalifikacyjne na stanowisko iOS gruntownie weryfikują zarówno podstawy, jak i zaawansowane zagadnienia języka Swift. Poniższe 25 pytań obejmuje tematy najczęściej poruszane przez rekruterów — od fundamentów języka po nowoczesne wzorce współbieżności. > **Jak korzystać z tego przewodnika** > > Każde pytanie zawiera szczegółową odpowiedź z przykładami kodu. Pytania są uporządkowane według rosnącego poziomu trudności — od podstaw do zagadnień zaawansowanych. ## Podstawy Swift ### 1. Jaka jest różnica między `let` a `var`? `let` deklaruje stałą, której wartość nie może być zmieniona po inicjalizacji, natomiast `var` deklaruje zmienną, którą można modyfikować. W przypadku typów referencyjnych (klas) `let` uniemożliwia ponowne przypisanie referencji, ale nie blokuje modyfikacji samego obiektu. ```swift // Constants.swift // let = constant, immutable value let maximumAttempts = 3 // maximumAttempts = 5 // ❌ Compile error // var = variable, mutable value var currentAttempt = 0 currentAttempt += 1 // ✅ OK // Careful with reference types class User { var name: String init(name: String) { self.name = name } } let user = User(name: "Alice") user.name = "Bob" // ✅ OK - modifying object, not reference // user = User(name: "Charlie") // ❌ Error - reassignment forbidden ``` **Dobra praktyka**: domyślnie należy stosować `let` i przełączać się na `var` wyłącznie wtedy, gdy mutacja jest niezbędna. Takie podejście sprawia, że kod jest bardziej przewidywalny i łatwiejszy do analizy. ### 2. Czym są optionale w Swift? Optionale reprezentują możliwy brak wartości. Optional może zawierać wartość danego typu albo `nil`. Swift wykorzystuje optionale, aby zagwarantować bezpieczeństwo na etapie kompilacji poprzez wymuszenie jawnej obsługi przypadków, gdy wartość może nie istnieć. ```swift // Optionals.swift // Declaring an optional with ? var username: String? = nil // Can hold a String or nil // Optional binding with if let (safe unwrapping) if let name = username { print("Hello, \(name)") // Only executes if username != nil } else { print("Anonymous user") } // Guard let for early return func greet(user: String?) { guard let name = user else { print("No user provided") return // Early exit if nil } print("Hello, \(name)") // name is guaranteed non-nil here } // Nil-coalescing operator (??) for default value let displayName = username ?? "Anonymous" // Force unwrapping (!) - DANGEROUS, avoid this // let forced = username! // Crashes if nil ``` ### 3. Jaka jest różnica między `struct` a `class`? `struct` to typ wartościowy (kopiowany przy przypisaniu), natomiast `class` to typ referencyjny (współdzieli tę samą instancję). Ta fundamentalna różnica wpływa na wydajność, zarządzanie pamięcią i zachowanie kodu. ```swift // ValueVsReference.swift // Struct = value type (copy) struct Point { var x: Int var y: Int } var p1 = Point(x: 10, y: 20) var p2 = p1 // Independent copy p2.x = 100 // Only modifies p2 print(p1.x) // 10 - p1 unchanged // Class = reference type (shared) class Rectangle { var width: Int var height: Int init(width: Int, height: Int) { self.width = width self.height = height } } let r1 = Rectangle(width: 10, height: 20) let r2 = r1 // Same shared instance r2.width = 100 // Modifies the shared instance print(r1.width) // 100 - r1 also modified! ``` **Kiedy co stosować**: - **Struct**: proste dane, wartości niemutowalne, brak potrzeby dziedziczenia - **Class**: istotna jest tożsamość obiektu, wymagane dziedziczenie, współdzielone zachowanie ### 4. Jak działa dopasowanie wzorców w `switch`? Instrukcja `switch` w Swift jest potężna i wyczerpująca — musi pokryć wszystkie możliwe przypadki. Obsługuje dopasowanie wzorców na typach, zakresach, krotkach oraz dodatkowe warunki za pomocą `where`. ```swift // PatternMatching.swift enum NetworkError: Error { case timeout case serverError(code: Int) case noConnection } func handleError(_ error: NetworkError) { switch error { case .timeout: print("Request timed out") case .serverError(let code) where code >= 500: print("Critical server error: \(code)") case .serverError(let code): print("Server error: \(code)") case .noConnection: print("No connection") } // No default needed: all cases covered } // Pattern matching on ranges and tuples let point = (x: 5, y: 10) switch point { case (0, 0): print("Origin") case (let x, 0): print("On X axis at \(x)") case (0...10, 0...10): print("In the 10x10 square") default: print("Elsewhere") } ``` ### 5. Czym są domknięcia (closures) i jaka jest ich składnia? Domknięcia to samodzielne bloki kodu, które przechwytują i przechowują referencje do zmiennych z otaczającego kontekstu. Stanowią odpowiednik lambd lub funkcji anonimowych znanych z innych języków. ```swift // Closures.swift // Full syntax let add: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in return a + b } // Shorthand syntax (inferred types, implicit return) let multiply: (Int, Int) -> Int = { $0 * $1 } // Trailing closure syntax let numbers = [3, 1, 4, 1, 5] let sorted = numbers.sorted { $0 > $1 } // [5, 4, 3, 1, 1] // Closure capturing a variable func makeCounter() -> () -> Int { var count = 0 // Captured variable return { count += 1 // Closure "closes over" count return count } } let counter = makeCounter() print(counter()) // 1 print(counter()) // 2 - count remembered between calls ``` > **Semantyka przechwytywania** > > Domknięcia domyślnie przechwytują zmienne przez referencję. Aby przechwycić przez wartość, należy użyć listy przechwytywania: `{ [count] in ... }`. ## Zarządzanie pamięcią i ARC ### 6. Jak działa ARC (Automatic Reference Counting)? ARC automatycznie zarządza pamięcią, zliczając silne referencje do każdej instancji klasy. Gdy licznik spadnie do zera, instancja zostaje zwolniona. W odróżnieniu od garbage collection, ARC jest deterministyczny i przewidywalny. ```swift // ARC.swift class Person { let name: String init(name: String) { self.name = name print("\(name) is initialized") } deinit { print("\(name) is deallocated") } } // Demonstrating lifecycle var person1: Person? = Person(name: "Alice") // refCount = 1 var person2 = person1 // refCount = 2 person1 = nil // refCount = 1 (not deallocated) person2 = nil // refCount = 0 → deinit called // Output: "Alice is deallocated" ``` ### 7. Czym jest cykl silnych referencji i jak mu zapobiegać? Cykl silnych referencji (retain cycle) występuje, gdy dwa obiekty trzymają silne referencje do siebie nawzajem, uniemożliwiając ich zwolnienie z pamięci. Słowa kluczowe `weak` i `unowned` przerywają takie cykle. ```swift // RetainCycle.swift class Department { let name: String var manager: Employee? // Strong reference init(name: String) { self.name = name } deinit { print("Department \(name) deallocated") } } class Employee { let name: String // weak prevents retain cycle - can become nil weak var department: Department? init(name: String) { self.name = name } deinit { print("Employee \(name) deallocated") } } // Without weak: retain cycle → memory leak // With weak: proper deallocation var dept: Department? = Department(name: "Engineering") var emp: Employee? = Employee(name: "Bob") dept?.manager = emp emp?.department = dept dept = nil // ✅ Deallocated thanks to weak emp = nil // ✅ Deallocated ``` ### 8. Jaka jest różnica między `weak` a `unowned`? Oba modyfikatory przerywają cykle silnych referencji, ale różnią się gwarancjami. `weak` jest opcjonalny i staje się `nil`, gdy obiekt, do którego się odwołuje, zostanie zwolniony. `unowned` zakłada, że obiekt zawsze istnieje — jeśli zostanie odczytany po zwolnieniu, program się zawiesi. ```swift // WeakVsUnowned.swift class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } } class CreditCard { let number: String // unowned because a card always exists with its customer unowned let customer: Customer init(number: String, customer: Customer) { self.number = number self.customer = customer } } // Card cannot exist without customer let customer = Customer(name: "Alice") customer.card = CreditCard(number: "1234", customer: customer) // If customer is deallocated, accessing card.customer would crash ``` **Zasada**: domyślnie należy stosować `weak`. `unowned` powinno być używane wyłącznie wtedy, gdy czas życia obiektu, do którego się odwołujemy, jest gwarantowany jako równy lub dłuższy. ## Protokoły i typy generyczne ### 9. Czym są protokoły w Swift? Protokół definiuje kontrakt (wymagane właściwości i metody), który muszą implementować zgodne typy. Protokoły umożliwiają polimorfizm i stanowią fundament Protocol-Oriented Programming (POP) w Swift. ```swift // Protocols.swift // Protocol definition protocol Drawable { var color: String { get set } // Required property (read/write) func draw() // Required method } // Protocol extension with default implementation extension Drawable { func draw() { print("Default drawing in \(color)") } } // Protocol conformance struct Circle: Drawable { var color: String var radius: Double // draw() inherits default implementation } struct Square: Drawable { var color: String var side: Double // Override default implementation func draw() { print("Square \(color) with side \(side)") } } // Polymorphic usage let shapes: [Drawable] = [Circle(color: "red", radius: 5), Square(color: "blue", side: 10)] shapes.forEach { $0.draw() } ``` ### 10. Czym jest typ stowarzyszony (associated type)? Typy stowarzyszone pozwalają protokołom definiować typy generyczne, które zostaną określone przez typy zgodne z protokołem. Ten mechanizm sprawia, że protokoły takie jak `Collection` są tak elastyczne. ```swift // AssociatedTypes.swift // Protocol with associated type protocol Container { associatedtype Item // Type defined by conformant var items: [Item] { get set } mutating func add(_ item: Item) func count() -> Int } // Implementation with Item = String struct StringBox: Container { typealias Item = String // Optional, Swift can infer var items: [String] = [] mutating func add(_ item: String) { items.append(item) } func count() -> Int { items.count } } // Implementation with Item = Int struct IntStack: Container { var items: [Int] = [] mutating func add(_ item: Int) { items.append(item) } func count() -> Int { items.count } } ``` ### 11. Jak działają typy generyczne? Typy generyczne pozwalają pisać elastyczny, wielokrotnego użytku kod, który działa z dowolnym typem. Eliminują duplikację kodu, zachowując jednocześnie bezpieczeństwo typów na etapie kompilacji. ```swift // Generics.swift // Generic function func swap(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp } // Type constraint with where func findIndex(of item: T, in array: [T]) -> Int? { for (index, element) in array.enumerated() { if element == item { return index } // Equatable required for == } return nil } // Generic struct struct Queue { private var elements: [Element] = [] mutating func enqueue(_ element: Element) { elements.append(element) } mutating func dequeue() -> Element? { guard !elements.isEmpty else { return nil } return elements.removeFirst() } } var intQueue = Queue() intQueue.enqueue(1) intQueue.enqueue(2) print(intQueue.dequeue()) // Optional(1) ``` ### 12. Czym jest protokół `Codable`? `Codable` (alias dla `Encodable & Decodable`) umożliwia automatyczną serializację typów Swift do formatów takich jak JSON i odwrotnie. Kompilator generuje implementację automatycznie, jeśli wszystkie właściwości same są Codable. ```swift // Codable.swift struct User: Codable { let id: Int let name: String let email: String let createdAt: Date // CodingKeys to map different JSON names enum CodingKeys: String, CodingKey { case id case name case email case createdAt = "created_at" // snake_case → camelCase } } // JSON decoding let json = """ { "id": 1, "name": "Alice", "email": "alice@example.com", "created_at": "2026-01-15T10:30:00Z" } """.data(using: .utf8)! let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 do { let user = try decoder.decode(User.self, from: json) print(user.name) // "Alice" } catch { print("Decoding error: \(error)") } // Encoding to JSON let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data = try encoder.encode(user) ``` ## Współbieżność i async/await ### 13. Jak działa async/await w Swift? `async/await` upraszcza kod asynchroniczny, pozwalając zapisywać operacje nieblokujące w sposób sekwencyjny. Funkcja oznaczona jako `async` może zostać zawieszona bez blokowania wątku, umożliwiając wykonywanie innych zadań. ```swift // AsyncAwait.swift // Asynchronous function func fetchUser(id: Int) async throws -> User { let url = URL(string: "https://api.example.com/users/\(id)")! // await suspends execution until response let (data, response) = try await URLSession.shared.data(from: url) guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { throw NetworkError.invalidResponse } return try JSONDecoder().decode(User.self, from: data) } // Calling from async context func loadUserProfile() async { do { let user = try await fetchUser(id: 42) print("User: \(user.name)") } catch { print("Error: \(error)") } } // Calling from synchronous context with Task func buttonTapped() { Task { await loadUserProfile() } } ``` ### 14. Czym jest Actor? Aktorzy to typy referencyjne chroniące swój wewnętrzny stan przed jednoczesnym dostępem z wielu wątków. Gwarantują, że tylko jedno zadanie w danym momencie może uzyskać dostęp do ich mutowalnych właściwości, eliminując wyścigi danych. ```swift // Actors.swift // Actor protects its state automatically actor BankAccount { private var balance: Double = 0 func deposit(_ amount: Double) { balance += amount // Automatic thread-safe access } func withdraw(_ amount: Double) -> Bool { guard balance >= amount else { return false } balance -= amount return true } func getBalance() -> Double { return balance } } // Usage - await required to access actor let account = BankAccount() Task { await account.deposit(100) let success = await account.withdraw(30) let balance = await account.getBalance() print("Balance: \(balance)") // 70 } ``` ### 15. Czym są `Task` i `TaskGroup`? `Task` tworzy jednostkę pracy asynchronicznej. `TaskGroup` umożliwia uruchomienie wielu zadań równolegle i zebranie ich wyników. ```swift // TaskGroup.swift // Simple Task let task = Task { return await fetchUser(id: 1) } let user = try await task.value // TaskGroup for parallelization func fetchMultipleUsers(ids: [Int]) async throws -> [User] { try await withThrowingTaskGroup(of: User.self) { group in // Launch all requests in parallel for id in ids { group.addTask { try await fetchUser(id: id) } } // Collect results as they complete var users: [User] = [] for try await user in group { users.append(user) } return users } } // All 3 requests run in parallel let users = try await fetchMultipleUsers(ids: [1, 2, 3]) ``` ### 16. Jak działa `@MainActor`? `@MainActor` zapewnia, że kod wykonuje się w wątku głównym. Jest to kluczowe dla aktualizacji interfejsu użytkownika, które zawsze muszą odbywać się w wątku głównym. ```swift // MainActor.swift // UI class annotated with @MainActor @MainActor class UserViewModel: ObservableObject { @Published var user: User? @Published var isLoading = false @Published var error: String? func loadUser() async { isLoading = true // ✅ On main thread automatically do { // Network operation on background thread user = try await fetchUser(id: 42) } catch { self.error = error.localizedDescription } isLoading = false // ✅ Automatic return to main thread } } // Or for a specific function func updateUI() async { await MainActor.run { // This block runs on main thread label.text = "Updated" } } ``` ## Wzorce i architektura ### 17. Czym jest wzorzec Delegate? Wzorzec Delegate pozwala obiektowi delegować określone obowiązki innemu obiektowi. Jest wszechobecny w UIKit (UITableViewDelegate, UITextFieldDelegate itp.). ```swift // DelegatePattern.swift // 1. Define the delegate protocol protocol DownloadManagerDelegate: AnyObject { func downloadDidStart() func downloadDidProgress(_ progress: Double) func downloadDidComplete(data: Data) func downloadDidFail(error: Error) } // 2. Class that uses the delegate class DownloadManager { // weak to avoid retain cycles weak var delegate: DownloadManagerDelegate? func startDownload(url: URL) { delegate?.downloadDidStart() // Simulated download Task { for progress in stride(from: 0.0, to: 1.0, by: 0.1) { try await Task.sleep(nanoseconds: 100_000_000) delegate?.downloadDidProgress(progress) } delegate?.downloadDidComplete(data: Data()) } } } // 3. Class that implements the delegate class ViewController: UIViewController, DownloadManagerDelegate { let manager = DownloadManager() override func viewDidLoad() { super.viewDidLoad() manager.delegate = self // Register as delegate } func downloadDidStart() { print("Started") } func downloadDidProgress(_ progress: Double) { print("\(progress * 100)%") } func downloadDidComplete(data: Data) { print("Complete") } func downloadDidFail(error: Error) { print("Error: \(error)") } } ``` ### 18. Czym jest wzorzec MVVM? MVVM (Model-View-ViewModel) oddziela logikę prezentacji od widoku. ViewModel udostępnia obserwowalne dane, które View wyświetla, bez znajomości szczegółów implementacji widoku. ```swift // MVVM.swift // Model struct Article: Identifiable { let id: UUID let title: String let content: String let publishedAt: Date } // ViewModel @MainActor class ArticleListViewModel: ObservableObject { @Published private(set) var articles: [Article] = [] @Published private(set) var isLoading = false @Published var errorMessage: String? private let repository: ArticleRepository init(repository: ArticleRepository = .shared) { self.repository = repository } func loadArticles() async { isLoading = true errorMessage = nil do { articles = try await repository.fetchArticles() } catch { errorMessage = "Failed to load articles" } isLoading = false } } // View (SwiftUI) struct ArticleListView: View { @StateObject private var viewModel = ArticleListViewModel() var body: some View { Group { if viewModel.isLoading { ProgressView() } else { List(viewModel.articles) { article in Text(article.title) } } } .task { await viewModel.loadArticles() } } } ``` ### 19. Na czym polega wstrzykiwanie zależności (Dependency Injection)? Wstrzykiwanie zależności polega na dostarczaniu zależności obiektowi z zewnątrz zamiast tworzenia ich wewnętrznie. Poprawia to testowalność i zmniejsza sprzężenie między komponentami. ```swift // DependencyInjection.swift // Protocol for abstraction protocol UserServiceProtocol { func fetchUser(id: Int) async throws -> User } // Real implementation class UserService: UserServiceProtocol { func fetchUser(id: Int) async throws -> User { // Real API call let url = URL(string: "https://api.example.com/users/\(id)")! let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode(User.self, from: data) } } // ViewModel with injection class ProfileViewModel: ObservableObject { private let userService: UserServiceProtocol // Constructor injection init(userService: UserServiceProtocol = UserService()) { self.userService = userService } func loadProfile(id: Int) async { // Uses injected service } } // Mock for testing class MockUserService: UserServiceProtocol { func fetchUser(id: Int) async throws -> User { return User(id: id, name: "Test User", email: "test@test.com") } } // In tests let viewModel = ProfileViewModel(userService: MockUserService()) ``` ### 20. Jak zaimplementować wzorzec Singleton? Singleton zapewnia, że klasa posiada tylko jedną, globalnie dostępną instancję. W Swift realizuje się to za pomocą statycznej właściwości z prywatnym inicjalizatorem. ```swift // Singleton.swift class NetworkManager { // Single globally accessible instance static let shared = NetworkManager() // Private initializer prevents creating other instances private init() { // Initial configuration } private let session = URLSession.shared func request(_ url: URL) async throws -> T { let (data, _) = try await session.data(from: url) return try JSONDecoder().decode(T.self, from: data) } } // Usage let user: User = try await NetworkManager.shared.request(url) ``` > **Ostrożnie z Singletonami** > > Singletony tworzą stan globalny, który utrudnia testowanie i rozdzielanie komponentów. Gdy to możliwe, lepszym rozwiązaniem jest wstrzykiwanie zależności. ## Zagadnienia zaawansowane ### 21. Czym jest `@escaping` w kontekście domknięć? Domknięcie jest oznaczone jako `@escaping`, gdy może zostać wywołane po zakończeniu funkcji, która je przyjmuje. Jest to częste w przypadku asynchronicznych callbacków oraz przechowywania domknięć. ```swift // Escaping.swift class DataLoader { // Storage of completion handlers private var completionHandlers: [() -> Void] = [] // @escaping because closure is stored and called later func loadData(completion: @escaping () -> Void) { completionHandlers.append(completion) DispatchQueue.global().async { // Async work... Thread.sleep(forTimeInterval: 1) DispatchQueue.main.async { // Closure called after loadData returns completion() } } } // Non-escaping by default: closure called before return func transform(data: Data, using transformer: (Data) -> String) -> String { return transformer(data) // Called immediately } } // With @escaping, watch for retain cycles class ViewController { var loader = DataLoader() var data: String? func load() { loader.loadData { [weak self] in // [weak self] avoids retain cycle self?.data = "Loaded" } } } ``` ### 22. Czym jest `@propertyWrapper`? Property wrappery enkapsulują logikę przechowywania i dostępu do właściwości. Pozwalają na wielokrotne wykorzystanie wzorców takich jak walidacja, logowanie czy persystencja. ```swift // PropertyWrapper.swift // Property wrapper for positive values only @propertyWrapper struct Positive { private var value: Int = 0 var wrappedValue: Int { get { value } set { value = max(0, newValue) } // Force positive } // Projected value accessible via $ var projectedValue: Bool { value > 0 } init(wrappedValue: Int) { self.wrappedValue = wrappedValue } } // Usage struct Player { @Positive var score: Int = 0 @Positive var health: Int = 100 } var player = Player() player.score = -50 // Becomes 0 (clamped) print(player.score) // 0 print(player.$score) // false (projectedValue) player.score = 100 print(player.$score) // true ``` ### 23. Czym są result buildery? Result buildery umożliwiają budowanie złożonych wartości za pomocą deklaratywnej składni. Ten mechanizm leży u podstaw składni DSL w SwiftUI. ```swift // ResultBuilder.swift // Result builder definition @resultBuilder struct StringBuilder { static func buildBlock(_ components: String...) -> String { components.joined(separator: " ") } static func buildOptional(_ component: String?) -> String { component ?? "" } static func buildEither(first component: String) -> String { component } static func buildEither(second component: String) -> String { component } } // Function using the builder func buildGreeting(@StringBuilder _ content: () -> String) -> String { content() } // Usage with declarative syntax let greeting = buildGreeting { "Hello" "and" "welcome" if Bool.random() { "!" } else { "." } } print(greeting) // "Hello and welcome !" or "Hello and welcome ." ``` ### 24. Jak działają `some` i typy nieprzezroczyste (opaque types)? `some` deklaruje typ nieprzezroczysty: dokładny typ jest znany kompilatorowi, ale ukryty przed wywołującym. Jest to niezbędne dla protokołów z typami stowarzyszonymi i umożliwia optymalizacje. ```swift // OpaqueTypes.swift // Without some: error because Collection has associated type // func makeCollection() -> Collection { ... } // ❌ Error // With some: exact type is hidden but consistent func makeArray() -> some Collection { return [1, 2, 3] // Always returns the same concrete type } // Used in SwiftUI for body struct ContentView: View { var body: some View { // Exact type inferred but hidden VStack { Text("Hello") Text("World") } } } // Difference with any (existential) func processAny(_ collection: any Collection) { // Can accept different types, runtime overhead } func processSome(_ collection: some Collection) { // Type fixed at compile time, no overhead } ``` ### 25. Czym są makra w Swift? Makra (Swift 5.9+) generują kod na etapie kompilacji. Redukują powtarzalny kod, zachowując jednocześnie bezpieczeństwo typów i możliwość debugowania. ```swift // Macros.swift // Freestanding macro: generates an expression let (x, y) = #unwrap(optionalX, optionalY) // Expands to: guard let x = optionalX, let y = optionalY else { ... } // Attached macro: modifies a declaration @Observable // Macro that generates Observable boilerplate class UserModel { var name: String = "" var email: String = "" } // Automatically generates @ObservationTracked, ObservationRegistrar, etc. // Macro for Codable with customization @Codable struct Product { let id: Int @CodableKey("product_name") let name: String // Renames JSON key @CodableIgnored var cache: Data? // Excludes from coding } // Creating a custom macro @attached(member, names: named(init)) public macro AutoInit() = #externalMacro(module: "MyMacros", type: "AutoInitMacro") @AutoInit struct Point { let x: Int let y: Int // init(x: Int, y: Int) generated automatically } ``` > **Debugowanie makr** > > W Xcode wystarczy kliknąć prawym przyciskiem na makro i wybrać "Expand Macro", aby zobaczyć wygenerowany kod. Przydatne przy analizie i debugowaniu. ## Podsumowanie Te 25 pytań obejmuje fundamenty, które każdy programista Swift powinien opanować, aby odnieść sukces na rozmowach rekrutacyjnych na stanowisko iOS. Od zarządzania pamięcią z ARC po nowoczesne wzorce współbieżności — każda koncepcja jest integralną częścią ekosystemu Swift. ### Lista kontrolna do powtórki - Opanowanie optionali i ich różnych metod rozpakowywania - Zrozumienie różnicy między typami wartościowymi a referencyjnymi - Umiejętność identyfikacji i rozwiązywania cykli silnych referencji za pomocą weak/unowned - Stosowanie async/await i aktorów do obsługi współbieżności - Implementacja wzorców Delegate, MVVM i Dependency Injection - Znajomość protokołów, typów generycznych i Codable - Zrozumienie zaawansowanych koncepcji: property wrappery, result buildery, makra ### Dodatkowe zasoby Oficjalna dokumentacja Swift pozostaje najlepszym źródłem wiedzy do pogłębiania tych zagadnień. Regularna praktyka z własnymi projektami i ćwiczeniami programistycznymi pomaga utrwalić zdobytą wiedzę. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/ios/top-25-swift-interview-questions