Saturday, October 29, 2016

ios swift try, try?, try!, defer and guard

do-try-catch block
Unlike other language, the basic usage of try-catch in swift is do-try-catch block as below, the do block will only run once, so do not mix it with do-while block.

  1. var vendingMachine = VendingMachine()
  2. vendingMachine.coinsDeposited = 8
  3. do {
  4. try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
  5. } catch VendingMachineError.invalidSelection {
  6. print("Invalid Selection.")
  7. } catch VendingMachineError.outOfStock {
  8. print("Out of Stock.")
  9. } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
  10. print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
  11. }
  
 try?
     As there are many cases, the operation's result is setting some value to a variable as below:

  1. let y: Int?
  2. do {
  3. y = try someThrowingFunction()
  4. } catch {
  5. y = nil
  6. }

  1. func someThrowingFunction() throws -> Int {
  2. // ...
  3. }
 
So swift introduce a simple syntax for it as try?, the above code is same as below
  1. let x = try? someThrowingFunction()


try!
When calling a throwable method, sometimes we know it will definitely not throw any exception, if so, it can be represented by try! as shown below. If, by any chance, the method does throw exception, then an runtime error will happen and terminate the app.

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")


defer
In other language, final clause is used to execute the clean up code when leaving try-catch block. In swift, the similar function is handled by defer statement. Although defer can be used without do-try-catch block. As long as the control leaves the block where defer is defined, then the defer clause will be executed.

  1. func processFile(filename: String) throws {
  2. if exists(filename) {
  3. let file = open(filename)
  4. defer {
  5. close(file)
  6. }
  7. while let line = try file.readline() {
  8. // Work with the file.
  9. }
  10. // close(file) is called here, at the end of the scope.
  11. }
  12. }

guard

Usually at the beginning of a function, pass-in parameters are validated, and if the validation failed, the function just returns.
Use "guard" instead of "if" in case when there is a good chance the condition return true. Unlike if, guard can only have an else clause to handle negative result. Usually the else clause will return from current method execution.
Different from if let statement, the guard let variable is available after the guard clause.

guard let myValue = myOptionalValue else {
return
}
print(myValue)

catch
When catching a particular type, enum or String in swift catch block, both is or as pattern match can be used

enum errorCode : Error {
    case NoModelURL
    case NoModel
}

extension String : Error {
}

Using is pattern match sample
    do {
            let mainContext = try createMainContext()
            print("main context is \(mainContext)")
            
            let firstVC = getFirstViewController()
            firstVC.managedObjectContext = mainContext
    }
    catch errorCode.NoModel {
            print("get no model error")
        }
    catch is errorCode {
            print("Get no model url error")
        }
    catch is String {
            print("string error happened")
        }
    catch {
            print("get error \(error)")
        }

Using as pattern match sample
    do {
            let mainContext = try createMainContext()
            print("main context is \(mainContext)")
            
            let firstVC = getFirstViewController()
            firstVC.managedObjectContext = mainContext
        }
        catch errorCode.NoModel {
                print("get no model error")
        }
        catch let errCode as errorCode {
            print("Get no model url error \(errCode)")
        }
        catch let errStr as String {
            print("Get no model url error \(errStr)")
        }
        catch let e {
            print("get error \(e)")
        }
using as pattern match is better, as it can access the Error object inside the catch handler block.



No comments:

Post a Comment