Do-Catch là một cấu trúc của ngôn ngữ Swift để xử lý lỗi, bắt các ngoại lệ được ném ra qua throw và thực thi khối mã tương ứng. Không giống try-catch truyền thống trong các ngôn ngữ khác, Swift yêu cầu đánh dấu rõ ràng các hàm có thể ném lỗi với bộ sửa đổi throws. Theo Swift.org, 2026, Do-Catch là cơ chế xử lý lỗi chính trong Swift, cung cấp an toàn kiểu.
Các điểm chính
Do-Catch là một cấu trúc trong Swift bao gồm một khối do, bên trong đó mã có khả năng ném lỗi được thực thi, và một hoặc nhiều khối catch xử lý lỗi đó. Khối do chứa các lời gọi đến các hàm throwing được đánh dấu bằng try, và các khối catch so khớp lỗi theo kiểu.
Swift thực hiện một mô hình xử lý lỗi có cấu trúc, khác với các ngoại lệ trong Objective-C. Ở đây, lỗi không phải là một ngoại lệ với việc mở xếp ngăn xếp, mà là một giá trị tuân thủ giao thức Error. Ném lỗi qua throw chuyển quyền điều khiển đến khối catch gần nhất mà không có chi phí mở xếp ngăn xếp.
Một tính năng chính của Swift là xử lý rõ ràng. Trình biên dịch không cho phép gọi hàm throwing mà không có try, do-catch hoặc cơ chế thay thế (try?, try!). Điều này loại bỏ các tình huống mà lỗi không được chú ý.
Trung tâm của việc xử lý lỗi trong Swift là giao thức Error. Bất kỳ kiểu nào tuân thủ giao thức này đều có thể được ném qua throw. Các lỗi thường được định nghĩa dưới dạng enum tuân thủ Error.
Error là một giao thức rỗng (đánh dấu). Nó không yêu cầu triển khai phương thức, chỉ cần tuân thủ. Trình biên dịch Swift sử dụng Error để kiểm tra tĩnh: một hàm có throws chỉ có thể ném một giá trị tuân thủ Error.
Một hàm được đánh dấu bằng throws phải được gọi với try. Nếu một throw xảy ra bên trong hàm đó, quyền điều khiển được chuyển đến do-catch đã gọi nó. Nếu lỗi không được xử lý ở bất kỳ đâu trong chuỗi gọi, nó sẽ lan truyền lên cấp trên.
enum FileError: Error {
case notFound
case permissionDenied
case corrupted(String)
}
func readFile(path: String) throws -> String {
guard FileManager.default.fileExists(atPath: path) else {
throw FileError.notFound
}
return try String(contentsOfFile: path)
}
rethrows là một bộ sửa đổi cho các hàm chấp nhận một closure throwing làm tham số. Nếu closure được truyền vào không ném lỗi, hàm rethrows có thể được gọi mà không cần try. Điều này cho phép viết các hàm bậc cao tổng quát tương thích với cả closure throwing và không throwing.
Swift hỗ trợ nhiều khối catch với so khớp lỗi dựa trên kiểu. Điều này tương tự when trong Kotlin hoặc switch theo kiểu: catch đầu tiên khớp sẽ được thực thi, các catch còn lại bị bỏ qua.
Mỗi khối catch có thể chứa một mẫu so khớp với một kiểu lỗi cụ thể. Swift kiểm tra các khối theo thứ tự, vì vậy các kiểu cụ thể hơn nên đứng trước các kiểu chung. Nếu không có mẫu nào khớp, khối catch không có mẫu sẽ được thực thi.
An toàn kiểu của Do-Catch cho phép xử lý từng lỗi riêng biệt hoặc kết hợp nhiều kiểu trong một khối thông qua so khớp mẫu phân cách bằng dấu phẩy. Điều này loại bỏ các chuỗi if-else cồng kềnh điển hình của Objective-C, nơi việc phân tích lỗi được thực hiện thông qua mã trả về hoặc NSError với kiểm tra miền và mã.
Swift cũng hỗ trợ catch where — so khớp với một điều kiện bổ sung. Ví dụ, bạn có thể lọc lỗi theo một mã hoặc văn bản cụ thể: catch URLError where error.code == .notConnectedToInternet. Điều này giảm số lượng khối catch trong khi duy trì độ chính xác.
Để gỡ lỗi các hàm throwing, Swift cung cấp sự phân biệt giữa lỗi và ngoại lệ. Một lỗi Swift là một giá trị trả về không yêu cầu mở xếp ngăn xếp. Các ngoại lệ Objective-C (@try/@catch) hoạt động ở cấp độ runtime và chỉ được sử dụng cho các lỗi nghiêm trọng. Do-Catch xử lý lỗi, không phải ngoại lệ, làm cho nó có thể dự đoán và hiệu quả.
Khi phát triển các thư viện và SDK, điều quan trọng là nhớ rằng các hàm throwing là một phần của hợp đồng công khai. Kiểu lỗi không được chỉ định trong chữ ký, vì vậy hãy ghi lại tài liệu những lỗi mà một hàm có thể ném trong các nhận xét hoặc thông qua các enum giống Result. Điều này giúp người dùng API viết các khối catch chính xác mà không cần xem xét triển khai.
Trong bối cảnh lập trình bất đồng bộ, Do-Catch với async/await giải quyết vấn đề callback hell. Trước đây trong Swift, việc xử lý lỗi trong mã bất đồng bộ yêu cầu các closure lồng nhau với kiểm tra Error? trong các trình xử lý hoàn thành. Với async/await và Do-Catch, mã throwing bất đồng bộ trông giống như mã đồng bộ, đơn giản hóa việc đọc và bảo trì các chuỗi yêu cầu phức tạp với xử lý lỗi ở mỗi bước.
do {
let content = try readFile(path: "/data/config.json")
process(content)
} catch FileError.notFound {
createDefaultConfig()
} catch FileError.permissionDenied {
requestAccess()
} catch FileError.corrupted(let detail) {
logCorruption(detail)
} catch {
print("Lỗi không xác định: \(error)")
}
Swift cung cấp ba cách để gọi các hàm throwing: try, try? và try!. Mỗi tùy chọn giải quyết một nhiệm vụ cụ thể và có những hạn chế riêng.
try được sử dụng bên trong khối do, và lỗi được xử lý trong catch. Đây là cách chính để gọi các hàm throwing. Trình biên dịch yêu cầu try phải ở trong một ngữ cảnh mà lỗi có thể được bắt.
try? chuyển đổi kết quả của một hàm throwing thành Optional. Nếu hàm ném lỗi, try? trả về nil, nếu không thì trả về Optional với giá trị thành công. Hữu ích cho các lời gọi mà lỗi có thể bỏ qua nhưng cần chỉ báo thành công.
try! ngăn chặn việc xử lý lỗi. Nếu hàm throwing ném lỗi, ứng dụng sẽ kết thúc với lỗi runtime. Chỉ sử dụng try! khi bạn hoàn toàn chắc chắn rằng lỗi không thể xảy ra — ví dụ, khi tải một tài nguyên được đóng gói.
// try? — bỏ qua lỗi, nhận được nil khi thất bại
if let data = try? Data(contentsOf: url) {
processData(data)
}
// try! — chỉ khi lỗi được đảm bảo không thể xảy ra
let bundled = try! String(contentsOfFile: "Assets/default.txt")
// try — tùy chọn tiêu chuẩn trong do-catch
do {
let result = try performNetworkRequest()
updateUI(result)
} catch {
showError(error)
}
Do-Catch được sử dụng tích cực trong phát triển iOS để làm việc với các API hệ thống. Hãy xem xét các kịch bản điển hình: làm việc với hệ thống tệp, Core Data và các yêu cầu mạng.
Nhiều phương thức của FileManager là throwing. Do-Catch cho phép xử lý chính xác việc thiếu tệp, tài nguyên đang bận hoặc không đủ quyền.
Phân tích cú pháp JSON qua JSONDecoder là một hoạt động throwing. Do-Catch bắt lỗi giải mã và lỗi mạng riêng biệt, cung cấp cho người dùng thông báo lỗi chính xác.
struct User: Codable {
let id: Int
let name: String
}
func fetchUser(id: Int) async throws -> User {
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)
}
// Lời gọi với xử lý
do {
let user = try await fetchUser(id: 42)
showUser(user)
} catch let error as URLError {
showNetworkAlert(error)
} catch let error as DecodingError {
showParseError(error)
} catch {
showGenericError(error)
}
Các nhà phát triển, đặc biệt là những người chuyển đổi từ các ngôn ngữ khác, thường mắc phải các lỗi đặc trưng khi sử dụng Do-Catch. Hãy xem xét những lỗi phổ biến nhất.
Câu hỏi thường gặp
Trong Swift, lỗi là một giá trị tuân thủ giao thức Error, không phải là ngoại lệ với mở xếp ngăn xếp. Các hàm throwing phải được đánh dấu rõ ràng bằng throws và trình biên dịch yêu cầu try khi gọi — điều này loại bỏ các lỗi không được xử lý tại thời điểm biên dịch.
Có, các hàm async cũng có thể là throws và do-catch hoạt động với chúng. Gọi một hàm async throwing yêu cầu try await bên trong khối do. Đây là cách tiêu chuẩn để xử lý lỗi trong mã Swift bất đồng bộ.
Có các lựa chọn thay thế: try? chuyển đổi lỗi thành nil, try! gây ra sự cố khi có lỗi và rethrows cho phép truyền lỗi từ một closure. Do-catch vẫn là cách chính để xử lý rõ ràng.
Swift không phân loại các lỗi được ném — bất kỳ hàm throwing nào cũng có thể ném bất kỳ kiểu nào tuân thủ Error. Phân chia xử lý thông qua so khớp trong catch theo các loại lỗi cụ thể.
Có, đó là một thực hành tốt. Định nghĩa AppError như một enum tuân thủ Error và chuyển đổi các lỗi hệ thống thành lỗi miền. Điều này thống nhất việc xử lý và cô lập lớp ứng dụng khỏi các chi tiết hệ thống.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm