swift-error handling (Err handling) (16)

Source: Internet
Author: User


Objective


Error handlingError Handlingis the process of responding to an error and recovering from an error. Swift provides advanced support for throwing, capturing, delivering, and manipulating recoverable errors at run time.



The subsections contain the following knowledge points:


    • Represents and throws an error
    • Handling Errors
    • Specify cleanup operations


Some operations do not guarantee that all code can be executed and will produce useful results, such as reading files from disk and data processing, the task will have a variety of failure possibilities, the specified path may be the file does not exist, the file does not have Read permission, the file encoding format is incompatible. Differentiating these error scenarios allows the program to resolve and handle some errors, and then report it to the user that it cannot resolve.



Note that error handling in Swift involves the wrong processing mode, which is used byCocoaandObjective-CNSError. That is, the type used in SwiftObjective-C.



It is important to note that this section of the content of the project code quality is very meaningful, but there should be a lot of beginners are not good at using, such as me,, in the use ofObjective-Cdevelopment, error handling I have only used assertions, and other useless or even do not understand. Sometimes, there are a lot of cases of error warning we will have a variety of ways to identify, such as pop-up windows, output reminders and so on. Here we describe several different ways of handling errors, and as for which is better, you need to practice it later in the project.


Sub-article details

  1. Represents and throws an error



    In Swift, errors are represented byErrorTypevalues that follow the protocol type. This null protocol represents a type that can be used as an error handling. Swift's enumeration types are particularly useful for shaping a set of related error scenarioserror conditions, and the associated values of enumerationsassiciated valuescan also provide additional information. For example, it can be said: In the game to operate the error situation of the auto-sale opportunity, throw the wrong usethrowskeyword:


    // 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
    }
    // throw an error, throwing an error will prompt the unexpected situation, indicating that the normal execution process can not be executed.
    Throw VendingMachineError.InsufficientFunds(coinsNeeded: 10) 

  2. Handling Errors



    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")

  3. Specify cleanup errors



    You can use adeferstatement to execute a set of statements before the code executes until you leave the current code snippet, which allows us to do the necessary cleanup work that should be performed, regardless of the way it was left in the current code segment, either by throwing an error or by areturnbreakcontinuesuch a similar statement.



    deferStatement to defer execution of code until the current scope exits. The statement consistsdeferof the keyword and the statements to be executed by the delay. Deferred statements do not include any code that would transfer control to the outside of the statement, suchbreakasreturna statement, or throw an error.



    Deferred actions are performed in the reverse order that they specify – meaning thatdeferthe code in the first statement is executeddeferafter the code in the second statement is executed, and so on. You can use statements even if you do not have code that involves error handlingdefer.



    The following example code uses adeferstatement to ensure thatopen(_:)the function has a correspondingclose(_:)invocation:


    // file
    Struct HandleFile {
    Func readline() throws -> String {
         // read the file
         Return "hello world"
    }
    }
    / / Method to determine whether the file exists
    Func exists(file: String) -> Bool {
    // execute the code, this assumes true
    Return true
    }
    //  open a file
    Func open(file: String) -> HandleFile {
    Let file = HandleFile()
    Return file
    }
    // close the file
    Func close(file: HandleFile) {
    }
    // This method is the place to display the defer usage. The above code is only used to ensure that the following method is executed without error.
    Func processFile(fileName: String) throws {
    If exists(fileName) {
         Let file = open(fileName)
         Defer {
             Close(file)
         }
         While let line = try? file.readline() {
             / / Process the file
             Print(line)
         }
    }
    } 
Summarize


About the usage of error handling even if I finished writing, I was confused, because I used to be almost useless, and the newly learned knowledge is very difficult to think of where to use, such as error transmission failure, since the Ming know not to throw errors, why writethrowingmethods, when the actual development needs to use this, anddeferSpecific when to use, what application scenarios, they have not encountered before, need to slowly go to grope. At the same time, I do not understand the time also checked the other article how to write, Chinese to find a good, click to view, write clearly more experienced, can be more reference.



Last night saw the little Plum Oscar works "Wilderness Hunter", really is a high-energy ah, across the screen can feel pain, feel cold.






swift-error handling (Err handling) (16)


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.