# 25 คำถามสัมภาษณ์ Swift ยอดนิยมสำหรับนักพัฒนา iOS > เตรียมตัวสำหรับการสัมภาษณ์ iOS ด้วย 25 คำถาม Swift ที่พบบ่อยที่สุด: optionals, closures, ARC, protocols, async/await และ pattern ขั้นสูง - Published: 2026-01-29 - Updated: 2026-04-12 - Author: SharpSkill - Tags: swift, ios, interview, career, apple - Reading time: 15 min --- การสัมภาษณ์เชิงเทคนิคสำหรับ iOS จะทดสอบความรู้ Swift ทั้งพื้นฐานและขั้นสูงอย่างละเอียด 25 คำถามต่อไปนี้ครอบคลุมหัวข้อที่ผู้สัมภาษณ์ถามบ่อยที่สุด ตั้งแต่พื้นฐานภาษาไปจนถึง pattern ของ concurrency สมัยใหม่ > **วิธีใช้คู่มือนี้** > > แต่ละคำถามมีคำตอบโดยละเอียดพร้อมตัวอย่างโค้ด คำถามเรียงตามระดับความยากที่เพิ่มขึ้น จากพื้นฐานไปจนถึงแนวคิดขั้นสูง ## พื้นฐาน Swift ### 1. ความแตกต่างระหว่าง `let` และ `var` คืออะไร? `let` ประกาศค่าคงที่ที่ไม่สามารถเปลี่ยนแปลงได้หลังจากกำหนดค่าเริ่มต้น ในขณะที่ `var` ประกาศตัวแปรที่สามารถเปลี่ยนแปลงได้ สำหรับ reference types (class) นั้น `let` ป้องกันการกำหนดค่า reference ใหม่ แต่ไม่ได้ป้องกันการแก้ไขตัว object เอง ```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 ``` **แนวปฏิบัติที่ดี**: ใช้ `let` เป็นค่าเริ่มต้น และเปลี่ยนเป็น `var` เฉพาะเมื่อจำเป็นต้องเปลี่ยนแปลงค่า วิธีนี้ทำให้โค้ดคาดเดาได้ง่ายและเข้าใจได้ดีขึ้น ### 2. อธิบาย optionals ใน Swift Optionals แสดงถึงความเป็นไปได้ที่ค่าจะไม่มีอยู่ Optional สามารถเก็บค่าของประเภทที่กำหนดหรือ `nil` ได้ Swift ใช้ optionals เพื่อรับประกันความปลอดภัยตอน compile โดยบังคับให้จัดการกรณีที่ค่าอาจไม่มีอย่างชัดเจน ```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. ความแตกต่างระหว่าง `struct` และ `class` คืออะไร? `struct` เป็น value type (ถูกคัดลอกเมื่อกำหนดค่า) ในขณะที่ `class` เป็น reference type (ใช้ instance เดียวกันร่วมกัน) ความแตกต่างพื้นฐานนี้ส่งผลต่อประสิทธิภาพ การจัดการหน่วยความจำ และพฤติกรรมของโค้ด ```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! ``` **เมื่อไหร่ควรใช้แบบไหน**: - **Struct**: ข้อมูลที่เรียบง่าย ค่า immutable ไม่ต้องการ inheritance - **Class**: identity สำคัญ ต้องการ inheritance พฤติกรรมที่ใช้ร่วมกัน ### 4. Pattern matching กับ `switch` ทำงานอย่างไร? `switch` ใน Swift มีความสามารถสูงและเป็น exhaustive: ต้องครอบคลุมทุกกรณีที่เป็นไปได้ รองรับ pattern matching กับประเภท range tuple และเงื่อนไขเพิ่มเติมด้วย `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. อธิบาย closures และ syntax ของมัน Closures คือบล็อกโค้ดที่ทำงานอิสระ สามารถจับและเก็บ reference ไปยังตัวแปรจากบริบทรอบข้าง Closures เทียบเท่ากับ lambda หรือ anonymous functions ในภาษาอื่น ```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 ``` > **Capture semantics** > > Closures จะจับตัวแปรแบบ reference โดยค่าเริ่มต้น หากต้องการจับแบบ value ให้ใช้ capture list: `{ [count] in ... }` ## การจัดการหน่วยความจำและ ARC ### 6. ARC (Automatic Reference Counting) ทำงานอย่างไร? ARC จัดการหน่วยความจำโดยอัตโนมัติด้วยการนับ strong references ไปยังแต่ละ instance ของ class เมื่อจำนวนลดลงเป็นศูนย์ instance นั้นจะถูก deallocate ต่างจาก garbage collection ตรงที่ ARC เป็น deterministic และคาดเดาได้ ```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. Retain cycle คืออะไร และป้องกันได้อย่างไร? Retain cycle เกิดขึ้นเมื่อสอง object ถือ strong reference ถึงกันและกัน ทำให้ไม่สามารถ deallocate ได้ keyword `weak` และ `unowned` ใช้เพื่อตัดวงจรเหล่านี้ ```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. ความแตกต่างระหว่าง `weak` และ `unowned` คืออะไร? ทั้งสองตัดวงจร retain cycle แต่มีการรับประกันที่ต่างกัน `weak` เป็น optional และจะกลายเป็น `nil` หาก object ที่ถูกอ้างอิงถูก deallocate `unowned` ถือว่า object มีอยู่เสมอและจะ crash หากเข้าถึงหลัง deallocate ```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 ``` **กฎ**: ใช้ `weak` เป็นค่าเริ่มต้น ใช้ `unowned` เฉพาะเมื่อ lifetime ของ object ที่ถูกอ้างอิงรับประกันว่าเท่ากันหรือยาวกว่า ## Protocols และ Generics ### 9. อธิบาย protocols ใน Swift Protocols กำหนดสัญญา (properties และ methods ที่จำเป็น) ที่ประเภทที่ conform ต้อง implement Protocols ทำให้เกิด polymorphism และเป็นรากฐานของ Protocol-Oriented Programming (POP) ใน 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. Associated type คืออะไร? Associated types ให้ protocols สามารถกำหนดประเภท generic ที่จะถูกระบุโดยประเภทที่ conform กลไกนี้ทำให้ protocols อย่าง `Collection` มีความยืดหยุ่นสูง ```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. Generics ทำงานอย่างไร? Generics ช่วยให้เขียนโค้ดที่ยืดหยุ่นและนำกลับมาใช้ซ้ำได้กับประเภทใดก็ได้ Generics หลีกเลี่ยงการเขียนโค้ดซ้ำในขณะที่ยังรักษาความปลอดภัยของประเภทตอน compile ```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. อธิบาย protocol `Codable` `Codable` (alias ของ `Encodable & Decodable`) ช่วยให้ serialize ประเภท Swift ไปยังและจากรูปแบบอย่าง JSON ได้โดยอัตโนมัติ Compiler จะสร้าง implementation ให้อัตโนมัติหากทุก property เป็น 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) ``` ## Concurrency และ async/await ### 13. async/await ใน Swift ทำงานอย่างไร? `async/await` ทำให้โค้ด asynchronous เรียบง่ายขึ้นโดยอนุญาตให้เขียนการดำเนินการแบบ non-blocking ในรูปแบบลำดับ ฟังก์ชัน `async` สามารถถูกระงับโดยไม่ block thread ทำให้ task อื่นสามารถทำงานได้ ```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. Actor คืออะไร? Actors เป็น reference types ที่ปกป้อง state ภายในจากการเข้าถึงพร้อมกัน Actors รับประกันว่ามีเพียง task เดียวเท่านั้นที่เข้าถึง mutable properties ได้ในเวลาเดียวกัน ซึ่งกำจัด data races ```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. อธิบาย `Task` และ `TaskGroup` `Task` สร้างหน่วยงาน asynchronous `TaskGroup` ช่วยให้สามารถรัน task หลายตัวแบบขนานและรวบรวมผลลัพธ์ ```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. `@MainActor` ทำงานอย่างไร? `@MainActor` รับประกันว่าโค้ดจะทำงานบน main thread ซึ่งจำเป็นอย่างยิ่งสำหรับการอัปเดต UI ที่ต้องดำเนินการบน main thread เสมอ ```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" } } ``` ## Patterns และสถาปัตยกรรม ### 17. อธิบาย Delegate pattern Delegate pattern ช่วยให้ object หนึ่งมอบหมายความรับผิดชอบบางอย่างให้กับ object อื่น Pattern นี้ใช้กันอย่างแพร่หลายใน UIKit (UITableViewDelegate, UITextFieldDelegate เป็นต้น) ```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. MVVM pattern คืออะไร? MVVM (Model-View-ViewModel) แยกตรรกะการแสดงผลออกจาก view ViewModel เปิดเผยข้อมูลที่สามารถ observe ได้ที่ View แสดง โดยไม่จำเป็นต้องรู้รายละเอียดของ View ```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. อธิบาย dependency injection Dependency injection คือการจัดหา dependencies ของ object จากภายนอกแทนที่จะสร้างภายใน วิธีนี้ช่วยปรับปรุง testability และลด coupling ```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. วิธี implement Singleton pattern? Singleton รับประกันว่า class มีเพียง instance เดียวที่เข้าถึงได้จากทุกที่ ใน Swift ใช้ static property และ private initializer ```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) ``` > **ข้อควรระวังเกี่ยวกับ Singleton** > > Singleton สร้าง global state ที่ทำให้การ test และ decoupling ยากขึ้น ควรใช้ dependency injection แทนเมื่อเป็นไปได้ ## แนวคิดขั้นสูง ### 21. อธิบาย `@escaping` สำหรับ closures Closure เป็น `@escaping` เมื่อสามารถถูกเรียกหลังจากฟังก์ชันที่รับมันได้ return ไปแล้ว กรณีนี้พบบ่อยกับ async callbacks และการเก็บ closure ```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. `@propertyWrapper` คืออะไร? Property wrappers ห่อหุ้มตรรกะการจัดเก็บและเข้าถึงของ property กลไกนี้ช่วยให้นำ pattern เช่น validation, logging หรือ persistence กลับมาใช้ซ้ำได้ ```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. อธิบาย result builders Result builders ช่วยให้สร้างค่าที่ซับซ้อนด้วย syntax แบบ declarative นี่คือกลไกที่อยู่เบื้องหลัง DSL syntax ของ 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. `some` และ opaque types ทำงานอย่างไร? `some` ประกาศ opaque type: ประเภทที่แท้จริง compiler รู้แต่ซ่อนจากผู้เรียก สิ่งนี้จำเป็นสำหรับ protocols ที่มี associated types และช่วยให้ทำ optimization ได้ ```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. อธิบาย Swift macros Macros (Swift 5.9+) สร้างโค้ดตอน compile ช่วยลด boilerplate ในขณะที่ยังคงความปลอดภัยของประเภทและสามารถ debug ได้ ```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 } ``` > **การ debug macros** > > ใน Xcode คลิกขวาที่ macro แล้วเลือก "Expand Macro" เพื่อดูโค้ดที่สร้างขึ้น มีประโยชน์สำหรับการทำความเข้าใจและ debug ## สรุป 25 คำถามเหล่านี้ครอบคลุมพื้นฐานที่นักพัฒนา Swift ทุกคนต้องเชี่ยวชาญเพื่อประสบความสำเร็จในการสัมภาษณ์ iOS ตั้งแต่การจัดการหน่วยความจำด้วย ARC ไปจนถึง concurrency patterns สมัยใหม่ แต่ละแนวคิดมีความเชื่อมโยงกันในระบบนิเวศของ Swift ### รายการตรวจสอบ - เชี่ยวชาญ optionals และวิธี unwrapping แบบต่างๆ - เข้าใจความแตกต่างระหว่าง value types และ reference types - รู้วิธีระบุและแก้ไข retain cycles ด้วย weak/unowned - ใช้ async/await และ actors สำหรับ concurrency - Implement Delegate, MVVM และ Dependency Injection patterns - เข้าใจ protocols, generics และ Codable - เชี่ยวชาญแนวคิดขั้นสูง: property wrappers, result builders, macros ### แหล่งข้อมูลเพิ่มเติม สำหรับการเรียนรู้เชิงลึก เอกสารอย่างเป็นทางการของ Swift ยังคงเป็นแหล่งอ้างอิงหลัก การฝึกฝนสม่ำเสมอด้วยโปรเจกต์ส่วนตัวและแบบฝึกหัดโค้ดช่วยให้เข้าใจแนวคิดเหล่านี้อย่างแม่นยำ --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/th/blog/ios/top-25-swift-interview-questions