25 คำถามสัมภาษณ์ Swift ยอดนิยมสำหรับนักพัฒนา iOS

เตรียมตัวสำหรับการสัมภาษณ์ iOS ด้วย 25 คำถาม Swift ที่พบบ่อยที่สุด: optionals, closures, ARC, protocols, async/await และ pattern ขั้นสูง

คำถามสัมภาษณ์ Swift สำหรับนักพัฒนา iOS

การสัมภาษณ์เชิงเทคนิคสำหรับ iOS จะทดสอบความรู้ Swift ทั้งพื้นฐานและขั้นสูงอย่างละเอียด 25 คำถามต่อไปนี้ครอบคลุมหัวข้อที่ผู้สัมภาษณ์ถามบ่อยที่สุด ตั้งแต่พื้นฐานภาษาไปจนถึง pattern ของ concurrency สมัยใหม่

วิธีใช้คู่มือนี้

แต่ละคำถามมีคำตอบโดยละเอียดพร้อมตัวอย่างโค้ด คำถามเรียงตามระดับความยากที่เพิ่มขึ้น จากพื้นฐานไปจนถึงแนวคิดขั้นสูง

พื้นฐาน Swift

1. ความแตกต่างระหว่าง let และ var คืออะไร?

let ประกาศค่าคงที่ที่ไม่สามารถเปลี่ยนแปลงได้หลังจากกำหนดค่าเริ่มต้น ในขณะที่ var ประกาศตัวแปรที่สามารถเปลี่ยนแปลงได้ สำหรับ reference types (class) นั้น let ป้องกันการกำหนดค่า reference ใหม่ แต่ไม่ได้ป้องกันการแก้ไขตัว object เอง

Constants.swiftswift
// 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 โดยบังคับให้จัดการกรณีที่ค่าอาจไม่มีอย่างชัดเจน

Optionals.swiftswift
// 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 เดียวกันร่วมกัน) ความแตกต่างพื้นฐานนี้ส่งผลต่อประสิทธิภาพ การจัดการหน่วยความจำ และพฤติกรรมของโค้ด

ValueVsReference.swiftswift
// 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

PatternMatching.swiftswift
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 ในภาษาอื่น

Closures.swiftswift
// 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 และคาดเดาได้

ARC.swiftswift
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 ใช้เพื่อตัดวงจรเหล่านี้

RetainCycle.swiftswift
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

WeakVsUnowned.swiftswift
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 ที่ถูกอ้างอิงรับประกันว่าเท่ากันหรือยาวกว่า

พร้อมที่จะพิชิตการสัมภาษณ์ iOS แล้วหรือยังครับ?

ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ

Protocols และ Generics

9. อธิบาย protocols ใน Swift

Protocols กำหนดสัญญา (properties และ methods ที่จำเป็น) ที่ประเภทที่ conform ต้อง implement Protocols ทำให้เกิด polymorphism และเป็นรากฐานของ Protocol-Oriented Programming (POP) ใน Swift

Protocols.swiftswift
// 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 มีความยืดหยุ่นสูง

AssociatedTypes.swiftswift
// 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

Generics.swiftswift
// Generic function
func swap<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

// Type constraint with where
func findIndex<T: Equatable>(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<Element> {
    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<Int>()
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

Codable.swiftswift
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 อื่นสามารถทำงานได้

AsyncAwait.swiftswift
// 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

Actors.swiftswift
// 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 หลายตัวแบบขนานและรวบรวมผลลัพธ์

TaskGroup.swiftswift
// 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 เสมอ

MainActor.swiftswift
// 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 เป็นต้น)

DelegatePattern.swiftswift
// 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

MVVM.swiftswift
// 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() }
    }
}

พร้อมที่จะพิชิตการสัมภาษณ์ iOS แล้วหรือยังครับ?

ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ

19. อธิบาย dependency injection

Dependency injection คือการจัดหา dependencies ของ object จากภายนอกแทนที่จะสร้างภายใน วิธีนี้ช่วยปรับปรุง testability และลด coupling

DependencyInjection.swiftswift
// 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

Singleton.swiftswift
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<T: Decodable>(_ 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

Escaping.swiftswift
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 กลับมาใช้ซ้ำได้

PropertyWrapper.swiftswift
// 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

ResultBuilder.swiftswift
// 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 ได้

OpaqueTypes.swiftswift
// 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 ได้

Macros.swiftswift
// 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 ยังคงเป็นแหล่งอ้างอิงหลัก การฝึกฝนสม่ำเสมอด้วยโปรเจกต์ส่วนตัวและแบบฝึกหัดโค้ดช่วยให้เข้าใจแนวคิดเหล่านี้อย่างแม่นยำ

เริ่มฝึกซ้อมเลย!

ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ

แท็ก

#swift
#ios
#interview
#career
#apple

แชร์

บทความที่เกี่ยวข้อง

คู่มือ SwiftUI สำหรับการสร้างอินเทอร์เฟซ iOS ที่ทันสมัย

SwiftUI: การสร้างอินเทอร์เฟซที่ทันสมัยสำหรับ iOS

คู่มือการสร้างอินเทอร์เฟซที่ทันสมัยด้วย SwiftUI: ไวยากรณ์แบบ declarative, คอมโพเนนต์, แอนิเมชัน และแนวปฏิบัติที่ดีที่สุดสำหรับ iOS 18

คำถามสัมภาษณ์ Data Science พร้อม neural networks แผนภูมิสถิติ และโค้ด Python บนพื้นหลังสีเข้ม

25 คำถามสัมภาษณ์ Data Science ยอดนิยมในปี 2026

คำถามสัมภาษณ์ Data Science ที่ครอบคลุมสถิติ machine learning การเตรียมฟีเจอร์ deep learning SQL และการออกแบบระบบ พร้อมตัวอย่างโค้ด Python และคำตอบเชิงลึกสำหรับปี 2026

แผนภาพแสดงระบบ Ownership และ Borrowing ของภาษา Rust

ทำความเข้าใจ Ownership และ Borrowing ใน Rust อย่างลึกซึ้ง สำหรับนักพัฒนาและผู้เตรียมสอบสัมภาษณ์

บทความเจาะลึกระบบ Ownership และ Borrowing ของ Rust ตั้งแต่พื้นฐานจนถึงขั้นสูง พร้อมตัวอย่างโค้ดจริงและแนวทางแก้ปัญหา Compiler Error ที่พบบ่อย เหมาะสำหรับการเตรียมสัมภาษณ์งาน