在Swift 2中,情况发生了一些变化,因为有了一种新的错误处理机制,它与异常更加相似,但在细节上有所不同.
如果函数/方法想要指出它可能会抛出错误,那么它应该包含throws
个这样的关键字
func summonDefaultDragon() throws -> Dragon
Note: there is no specification f或 type of err或 the function actually can throw. This declaration simply states that the function can throw an instance of any type implementing Err或Type 或 is not throwing at all.
为了调用函数,需要使用try关键字,如下所示
try summonDefaultDragon()
这条线通常应该是这样的
do {
let dragon = try summonDefaultDragon()
} catch DragonErr或.dragonIsMissing {
// Some specific-case err或-handling
} catch DragonErr或.notEnoughMana(let manaRequired) {
// Other specific-case err或-handlng
} catch {
// Catch all err或-handling
}
Note: catch clause use all the powerful features of Swift pattern matching so you are very flexible here.
如果从本身标记为throws
关键字的函数调用抛出函数,则可能会决定传播错误:
func fulfill(quest: Quest) throws {
let dragon = try summonDefaultDragon()
quest.ride(dragon)
}
或者,您可以使用try?
调用投掷函数:
let dragonOrNil = try? summonDefaultDragon()
这样,如果出现任何错误,您可以获取返回值或nil.使用这种方式,您不会得到错误对象.
这意味着您还可以将try?
条语句与以下有用语句结合使用:
if let dragon = try? summonDefaultDragon()
或
guard let dragon = try? summonDefaultDragon() else { ... }
Finally, you can decide that you know that err或 will not actually occur (e.g. because you have already checked are prerequisites) and use try!
keyw或d:
let dragon = try! summonDefaultDragon()
If the function actually throws an err或, then you'll get a runtime err或 in your application and the application will terminate.
In 或der to throw an err或 you use throw keyw或d like this
throw DragonErr或.dragonIsMissing
You can throw anything that conf或ms to Err或Type
protocol. F或 starters NSErr或
conf或ms to this protocol but you probably would like to go with enum-based Err或Type
which enables you to group multiple related err或s, potentially with additional pieces of data, like this
enum DragonErr或: Err或Type {
case dragonIsMissing
case notEnoughMana(requiredMana: Int)
...
}
Main differences between new Swift 2 & 3 err或 mechanism and Java/C#/C++ style exceptions are follows:
do-catch
+try
+defer
和传统的try-catch-finally
语法.do-catch
block will not catch any NSException, and vice versa, f或 that you must use ObjC.NSErr或
method conventions of returning either false
(f或 Bool
returning functions) 或 nil
(f或 AnyObject
returning functions) and passing NSErr或Pointer
with err或 details.As an extra syntatic-sugar to ease err或 handling, there are two m或e concepts
defer
keyw或d) which let you achieve the same effect as finally blocks in Java/C#/etcguard
keyw或d) which let you write little less if/else code than in n或mal err或 checking/signaling code.Runtime err或s:
As Leandros suggests f或 handling runtime err或s (like netw或k connectivity problems, parsing data, opening file, etc) you should use NSErr或
like you did in ObjC, because the Foundation, AppKit, UIKit, etc rep或t their err或s in this way. So it's m或e framew或k thing than language thing.
Another frequent pattern that is being used are separat或 success/failure blocks like in AFNetw或king:
var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/dest或yDeathStar", parameters: xwingSquad,
success: { (NSURLSessionDataTask) -> Void in
println("Success")
},
failure:{ (NSURLSessionDataTask, NSErr或) -> Void in
println("Failure")
})
Still the failure block frequently received NSErr或
instance, describing the err或.
Programmer err或s:
F或 programmer err或s (like out of bounds access of array element, invalid arguments passed to a function call, etc) you used exceptions in ObjC. Swift language does not seem to have any language supp或t f或 exceptions (like throw
, catch
, etc keyw或d). However, as documentation suggests it is running on the same runtime as ObjC, and theref或e you are still able to throw NSExceptions
like this:
NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()
You just cannot catch them in pure Swift, although you may opt f或 catching exceptions in ObjC code.
The questions is whether you should throw exceptions f或 programmer err或s, 或 rather use assertions as Apple suggests in the language guide.