Skip to Content

Closures trong Swift

1. Giới thiệu

Closures là anonymous functions có thể capture và lưu trữ references đến biến và hằng số.

2. Cú pháp cơ bản

// Cú pháp đầy đủ let greet = { (name: String) -> String in return "Hello, \(name)!" } print(greet("Alice")) // Hello, Alice!

3. Cú pháp ngắn gọn

let numbers = [1, 2, 3, 4, 5] // Đầy đủ let doubled1 = numbers.map({ (n: Int) -> Int in return n * 2 }) // Inferring type let doubled2 = numbers.map({ n in return n * 2 }) // Implicit return let doubled3 = numbers.map({ n in n * 2 }) // Shorthand argument names let doubled4 = numbers.map({ $0 * 2 }) // Trailing closure let doubled5 = numbers.map { $0 * 2 }

4. Trailing Closure

func performOperation(_ operation: () -> Void) { operation() } // Trailing closure syntax performOperation { print("Hello!") } // Multiple trailing closures func fetch( onSuccess: (String) -> Void, onError: (Error) -> Void ) { onSuccess("Data") } fetch { data in print("Got: \(data)") } onError: { error in print("Error: \(error)") }

5. Closures với Collections

let numbers = [3, 1, 4, 1, 5, 9, 2, 6] // filter let evens = numbers.filter { $0 % 2 == 0 } print(evens) // [4, 2, 6] // sorted let sorted = numbers.sorted { $0 < $1 } // reduce let sum = numbers.reduce(0) { $0 + $1 } print(sum) // 31 // compactMap let strings = ["1", "two", "3"] let ints = strings.compactMap { Int($0) } print(ints) // [1, 3]

6. Capturing Values

func makeCounter() -> () -> Int { var count = 0 return { count += 1 return count } } let counter = makeCounter() print(counter()) // 1 print(counter()) // 2 print(counter()) // 3

7. Capture List

class ViewController { var name = "Main" func doSomething() { // Capture self weakly để tránh retain cycle let closure = { [weak self] in guard let self = self else { return } print(self.name) } closure() } }

8. @escaping Closures

class NetworkManager { var completionHandler: ((String) -> Void)? func fetch(completion: @escaping (String) -> Void) { // Closure được lưu để gọi sau completionHandler = completion DispatchQueue.main.async { completion("Data loaded") } } }

9. @autoclosure

func logIfNeeded(_ condition: Bool, message: @autoclosure () -> String) { if condition { print(message()) } } logIfNeeded(true, message: "Expensive string: \(computeValue())") // Chỉ compute khi condition = true

10. Ví dụ thực tế

struct User: Codable { let name: String let age: Int } func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void) { URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(error)) return } guard let data = data else { return } do { let users = try JSONDecoder().decode([User].self, from: data) completion(.success(users)) } catch { completion(.failure(error)) } }.resume() }

📝 Tóm tắt

  • Closure: { (params) -> ReturnType in body }
  • $0, $1 shorthand cho parameters
  • Trailing closure syntax cho code gọn
  • @escaping khi closure được lưu/gọi sau
  • [weak self] tránh retain cycles
  • @autoclosure cho lazy evaluation
Last updated on