When an error is thrown in a place, the code in that place must be responsible for handling the error-such as correcting the problem, trying another way, or prompting the user for the problem. There are 4 ways to handle errors in Swift: One, pass the error that the function throws to the code that called the function, two, handle the error with thedo-catchstatement, and three, treat the error as an optional type, and assert that this error does not occur at all.
These four different error handling methods are described below. At the same time, in order to quickly navigate to the place where the error is thrown, add atrykeyword, ortry?such variant, before invoking a function, method, or constructor that can throw an errortry!. The use of Swift,trycatchand thethrowerror handling of these methods, do not involve stack unwindingStack unwindingand high performance. In this case, thethrowperformance characteristics of the statement can bereturncomparable to the statement. (P.S. This passage tells us not to worry about the burden of dealing with errors, we simply throw them where we need to throw them, and the Swift language itself is optimized.) )
-
throwingpassing errors with functions
Usethrowskeywords to identify a function, method, or constructor that can throw an error. Added after the argument list in the function declarationthrows. Athrowsfunction that is identified is called athrowingfunction. If the function has a return value type, thethrowskeyword needs to be written in->front of the arrow:
// throwing function without return argument
Func canThrowErrors() throws {
// function body
}
// with return parameters
Func canThrowErrors() throws -> String {
// function body
Return "hello world"
}
Athrowingfunction throws an error from the inside and passes to the area where the function is called. Note that onlythrowingfunctions can pass errors. Anythrowingerror that is thrown inside a non-function can only be handled inside this function.
In the following exampleVendingMechine, the class has avend(itemNamed:)method that, if the required item does not exist, is out of stock, or spends more than the amount invested, the method throws a corresponding oneVendingMachineError.
// Define the type of error, an error situation that can occur in a game vending machine
Enum VendingMachineError: ErrorType {
Case InvalidSelection // Invalid selection
Case InsufficientFunds(coinsNeeded: Int) // Gold is insufficient and prompts for missing quantity
Case OutOfStack // Out of stock
}
// product attributes
Struct Item {
Var price: Int // price
Var count: Int // quantity
}
// vending machine
Class VendingMachine {
// Product list, note that the price attribute attribute cannot be code-completed, and the following count can be completed.
Var inventory = ["Candy Bar": Item(price: 12, count: 5),
"Chips": Item(price: 10, count: 4),
"Pretzel": Item(price: 15, count: 8)]
// remaining gold coins
Var coinDeposited = 0
// Assign a snack method,,, P.S. Can you learn some English words?
Private func dispenceSnack(snack: String) {
Print("dispence \(snack)") // Print what snacks are distributed
}
// throw an error, as for the usage of guard, I have said in more detail before.
Func vend(itemNamed name: String) throws {
Guard var item = inventory[name] else {
Throw VendingMachineError.InvalidSelection // There are no selected items
}
Guard item.count > 0 else {
Throw VendingMachineError.OutOfStack // insufficient stock
}
Guard item.price <= coinDeposited else {
Throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinDeposited) // Insufficient gold coins
}
// After the purchase is completed, the vending machine inventory changes
coinDeposited -= item.price
Item.count -= 1
Inventory[name] = item
dispenceSnack(name)
}
}
For aguardmore detailed description of the usage before, click View. Here is a brief:guarduseifthe same, but must follow oneelse, that is, as long asguardthe following statement is set up, go down, otherwise walk theelsestatement. Focus:guardThe scope of the action is to contain its curly braces!
throwingThe function can only pass errors, but it cannot handle the error-either by using ado-catchstatement,try?ortry!by handling the error, or by continuing to pass these errors down.
Here we need to emphasize a bit, cantryonly pass the error, and can not solve the error, buttry?andtry!yet. And as long as it is called to throw the wrong method, you must usetrythis keyword, as for the back plus?or!, or nothing, look at the individual needs.
// Define a dictionary that shows everyone's favorite snacks
Let favoriteSnacks = ["Jack": "Chips",
"Tom": "Milk",
"Rose": "Meat"]
// Buy a favorite snack
Func buyFavoriteSnacks(person: String, vendingMachine: VendingMachine) throws {
Let snackName = favoriteSnacks[person] ?? "Candy Bar"
// The following try must be added, because calling a throwing function must use try to get the thrown error
// This is actually just passing the error
Try vendingMachine.vend(itemNamed: snackName)
}
-
UsingDo-Catchprocessing errors
You can use ado-catchstatement to run a closure code to do error handling. If thedocode in the statement runs out of an error, the error willcatchmatch the statement to determine which statement will handle it (a somewhat similarSwitchusage). Here isdo-catchthe general form of the statement:
Do {
Try expression // throwing function
Statements // function body, which is also the execution code under normal circumstances
} catch pattern 1 { // match error
Statements
} catch pattern 2 where condition {
// Where is the condition here I don't know what the specific role is, the textbook is written like this, but the following example code does not reflect this. Temporarily it is a confusing point, but it does not affect the use.
Statements
}
catchwrite a pattern in the backpatternto indicate what kind of error the statement can handle. If acatchstatement does not have a pattern, the statement can match any error (similar) andSwitchbind thedefaulterror to a local constant with a namename. (This sentence I do not understand the moment, thisnameis nothing to understand, the textbook provides aPatternsreference link, click to view)
catchThe statement does notdohave to handle every possible error thrown by the code in the statement. If there is nocatchstatement to handle the error, the error propagates to the surrounding scope. However, the error must be handled by one of the surrounding scopes: either a peripheraldo-catcherror-handling statement or athrowingfunction's interior.
For example, the following code handlesVendingMachineErrorall three enumeration instances of an enumeration type, but all other errors, that are not in the three cases, must be handled by the scope around it.
// instance vending machine
Var vendingMachine = VendingMachine()
vendingMachine.coinDeposited = 8
Do {
// Here I took the error passed in the above code.
Try buyFavoriteSnacks("Tom", vendingMachine: vendingMachine)
// Here's the code that executes under normal conditions, ie no errors are thrown
Print("Execute code when no error is thrown")
} catch VendingMachineError.InvalidSelection {
Print("What to do if you don't have an item")
} catch VendingMachineError.OutOfStack {
Print("What to do if you are out of stock")
} catch VendingMachineError.InsufficientFunds(let coinNeeded) { // The inside of the parentheses is the value passed in
Print("Gold insufficient, missing \(coinNeeded)")
}
// Output: insufficient gold coins, missing 2
// If: vendingMachine.coinDeposited = 10, output: code when there is no error
// If: try buyFavoriteSnacks("Tom", vendingMachine: vendingMachine), Output: What to do if there is no item selected
// Note: The content of the point after VendingMachineError in the above code is not code-completed.
In fact, for the above said "but all other errors, that does not belong to the above three cases, it must be dealt with by the scope of its surrounding", how to deal with, I am not very clear, the personal feeling is at the end of writing acatch, without any conditions, similarswitchdefault, But I'm not sure if I want to deal with it, and I don't write it.
-
Converting an error to an optional value
You can usetry?it to handle errors by converting them to an optional value. Iftry?an error is thrown when evaluating an expression, the value of the expression isnil.
Personally, this is similar to a cut, and there are no different errors that are thrown by using enumeration values in the example code above. When you use it,try?you simply throw an error, and the expression is madenil, and you don't care what went wrong. In most cases, it istry?possible to write concise error-handling code.
The following code snippet showstry?the basic usage as well asdo-catchthe contrast, in which thexeffect ofyprocessing is the same:
Func someThrowErrorsFuncation() throws -> Int {
// function body containing the error code thrown
}
// Use try? to handle errors
Let x = try? someThrowErrorsFuncation()
// do-catch processing syntax with the same effect as try?
Let y: Int?
Do {
Try someThrowErrorsFuncation()
} catch {
y = nil
}
note that,try?when used, regardless of the type returned by the expression, the received expression is an optional type, as in the above codexy.
If the method fails to returnnil, which is the error thrown when usingnil, then usetry?, very concise:
// method of getting data
Func fetchData() -> Data? {
If let data = try? fetchDataFromDisk() { return data } // If you can successfully get data from disk
If let data = try? fetchDataFromServer() { return data } // If the data can be successfully retrieved from the server
Return nil // can't get data
}
-
-
Invalidate error Delivery
Sometimes when we write code, we know that athrowingfunction doesn't actually throw an error when it runs. In this condition, the pre-expression of the error can betry!invalidated, and the call is wrapped in a runtime assertionruntime assertionto conclude that no error is thrown. If you actually throw an error, you get a run-time error.
Here is a function that loads a picture, and theloadImage(_:)function loads the picture under the specified path, and throws an error if the picture cannot be loaded. The sample code loads and applies the regulation regulation bound picture, which is the image inside the app, and the runtime obviously does not throw an error, which can be invalidated with error delivery:
lettry! loadImage("./Resources/default.png")