enum VendingMachineError:ErrorType{
    case InvaildSelection //选择无效
    case InsufficientFunds(coinsNeeded:Int) //金额不足
    case OutOfStock //缺货无效
}

enum GetJSONError: ErrorType {
    case Forbidden, NotFound
}
struct Item {
    var price:Int
    var count:Int
}
class ViewController: UIViewController {
    
    func getJSON(aaa:Int) throws -> String {
        let a = aaa
        if a == 403 {
            throw GetJSONError.Forbidden
        }
        else if a == 404 {
            throw GetJSONError.NotFound
        }
        return "return JSON String Success"

    }
    
    
    
    var inventory = [
        "Candy Bar":Item(price: 12, count: 7),
        "Chips":Item(price: 10, count: 4),
        "Pretzels":Item(price: 7, count: 11)
    ]
    var coinsDeposited=4
    func dispenseSnack(snack:String){
        print("Dispensing\(snack)")
    }
    func vend(itemNamed name:String) throws{
        guard var item=inventory[name] else{
            throw VendingMachineError.InvaildSelection
        }
        guard item.count > 0 else{
            throw VendingMachineError.OutOfStock
        }
        guard item.price <= coinsDeposited else{
         
            throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }
        coinsDeposited -= item.price
        --item.count
        inventory[name]=item
        dispenseSnack(name)
    }
    //错误处理
     //错误处理是响应错误以及从错误中恢复的过程。
     //可选类型用来表示值可能为空,但是当执行失败的时候,通常要去了解此次失败是由何引起,代码中就可以做出与之相应的反应
     //swift中,错误用遵循ErrorType协议类型的值来表示。这个空协议表示一种可以用做错误处理的类型。
     //用throws关键字来标识一个可抛出错误的函数,方法或是构造器。在函数声明中的参数列表之后加上throws,如果这个函数还有返回值类型,throws关键词需要写在箭头的前面
    
     //一个throwing函数从其内部抛出错误,并传递到该函数被调用时所在的区域中
     //只有throwing函数可以传递错误。任何在某个非throwing函数内部抛出的错误只能在此函数内处理
    override func viewDidLoad() {
        super.viewDidLoad()
        
                do{
                    try vend(itemNamed: "Pretzels")
                    
                } catch VendingMachineError.InvaildSelection {
                    print("InvaildSelection")
                } catch VendingMachineError.OutOfStock {
                    print("OutOfStock")
                } catch VendingMachineError.InsufficientFunds(let myCoinsNeed){
                    print(myCoinsNeed)
                }catch{
                    print("error catched!")
                } //3
        
        
        do{
            let json = try getJSON(404)
            print(json)
        } catch GetJSONError.Forbidden {
            print("403 Forbidden")
        } catch GetJSONError.NotFound {
            print("404 Not Found")
        } catch {
            print("error catched!")
        }//404 Not Found
        
        
        //将错误转换成可选值
         //可以使用try?通过将其转换成一个可选值来处理错误。如果在评估try?表达式时一个错误被抛出,那么这个表达式的值就是nil。
        let json = try?  getJSON(404)  //如果不加问号则会报错:Errors thrown from here are not handled
        print(json)//nil
        
        //let json = try? getJSON(404)等价于:
        let json2 : String?
        do{
          json2 = try getJSON(404)
        }catch{
          json2 = nil
        }
        print(json2)//nil
        
        
        //使错误传递失败
         //有时你知道某个throwing函数实际上运行时是不会抛出错误的。在这种条件下,可以在表达式前面写try!来使错误传递失败,并且调用包装在一个运行时断言中来断定不会有错误输出。如果实际上确实抛出了错误,就会得到一个运行时错误
        
        //指定清理操作
         //可以使用defer语句在代码执行到要离开当前的代码段之前去执行一套语句。该语句让你能够做一些应该被执行的必要清理工作。defer语句将代码的执行延时到当前的作用域之前。
        
        
    }
//    func processFile(filename:String)throws{
//        if exists(filename){
//            let file = open(filename)
//            defer{
//                close(file)
//            }
//            while let line = try file.readline(){
//                //处理文件
//            }
//            //作用域的最后调用close(file)
//        }
//    }
    
    
//    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//        //保存触摸起始位置
//       let point : CGPoint  = ((touches as NSSet).anyObject()?.locationInView(self.view))!
//         maskLayer.frame=CGRectMake(point.x-50,point.y-50, 100,100)
//    }
    
    //UITouch的属性和方法:
    //view :属性,触摸始于那个视图
    //window:属性,触摸始于那个窗口
    //locationInView:方法,触摸在指定视图中的当前位置
    //previousLocationView:方法,触摸在指定视图中的前一个位置
//    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
//        //计算位移=当前位置-起始位置
//        let point:CGPoint  = ((touches as NSSet).anyObject()?.locationInView(self.view))!
//         maskLayer.frame=CGRectMake(point.x-50,point.y-50, 100,100)
//    }
//    
}