Khi gọi một hàm được khai báo bằng throws
Swift, bạn phải chú thích trang gọi hàm với try
hoặc try!
. Ví dụ, đưa ra một chức năng ném:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
chức năng này có thể được gọi là:
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
Ở đây chúng tôi chú thích cuộc gọi với try
, gọi cho người đọc rằng hàm này có thể đưa ra một ngoại lệ và bất kỳ dòng mã nào sau đây có thể không được thực thi. Chúng ta cũng phải chú thích chức năng này throws
, bởi vì chức năng này có thể ném một ngoại lệ (nghĩa là khi willOnlyThrowIfTrue()
ném, sau đó foo
sẽ tự động bật lại ngoại lệ lên trên.
Nếu bạn muốn gọi một hàm được khai báo là có thể ném, nhưng cái mà bạn biết sẽ không ném trong trường hợp của bạn vì bạn đang cung cấp cho nó đầu vào chính xác, bạn có thể sử dụng try!
.
func bar() {
try! willOnlyThrowIfTrue(false)
}
Bằng cách này, khi bạn đảm bảo rằng mã sẽ không bị ném, bạn không cần phải thêm mã soạn sẵn để vô hiệu hóa lan truyền ngoại lệ.
try!
được thi hành tại thời gian chạy: nếu bạn sử dụng try!
và chức năng không kết thúc ném, sau đó thực hiện của chương trình của bạn sẽ được chấm dứt với một lỗi runtime.
Hầu hết các mã xử lý ngoại lệ sẽ trông giống như ở trên: hoặc bạn chỉ cần truyền các ngoại lệ lên trên khi chúng xảy ra hoặc bạn thiết lập các điều kiện sao cho các ngoại lệ có thể bị loại trừ. Bất kỳ việc dọn sạch các tài nguyên khác trong mã của bạn sẽ xảy ra thông qua việc hủy đối tượng (tức là deinit()
) hoặc đôi khi qua defer
mã ed.
func baz(value: Bool) throws {
var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
var data = NSData(contentsOfFile:filePath)
try willOnlyThrowIfTrue(value)
// data and filePath automatically cleaned up, even when an exception occurs.
}
Nếu vì bất kỳ lý do gì bạn đã dọn sạch mã cần chạy nhưng không có deinit()
chức năng, bạn có thể sử dụng defer
.
func qux(value: Bool) throws {
defer {
print("this code runs when the function exits, even when it exits by an exception")
}
try willOnlyThrowIfTrue(value)
}
Hầu hết các mã liên quan đến các ngoại lệ chỉ đơn giản là chúng truyền lên cho người gọi, dọn dẹp trên đường đi qua deinit()
hoặc defer
. Điều này là do hầu hết các mã không biết phải làm gì với lỗi; nó biết điều gì đã sai, nhưng nó không có đủ thông tin về những gì mã cấp cao hơn đang cố làm để biết phải làm gì về lỗi. Nó không biết nếu trình bày một hộp thoại cho người dùng là phù hợp, hoặc nếu nó nên thử lại, hoặc nếu một cái gì đó khác là phù hợp.
Mã cấp cao hơn, tuy nhiên, nên biết chính xác phải làm gì trong trường hợp có lỗi. Vì vậy, các trường hợp ngoại lệ cho phép các lỗi cụ thể nổi lên từ nơi chúng xảy ra ban đầu đến nơi chúng có thể được xử lý.
Xử lý các trường hợp ngoại lệ được thực hiện thông qua các catch
báo cáo.
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
Bạn có thể có nhiều câu lệnh bắt, mỗi câu bắt một loại ngoại lệ khác nhau.
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
Để biết thêm chi tiết về các thực tiễn tốt nhất có ngoại lệ, hãy xem http://exceptionsafecode.com/ . Nó đặc biệt nhắm vào C ++, nhưng sau khi kiểm tra mô hình ngoại lệ Swift, tôi tin rằng những điều cơ bản cũng áp dụng cho Swift.
Để biết chi tiết về cú pháp Swift và mô hình xử lý lỗi, hãy xem cuốn sách Ngôn ngữ lập trình Swift (Phát hành trước Swift 2) .