Swift 系统学习 22 分析错误的三个阶段 (枚举和结构体相关)

//: Playground - noun: a place where people can play

import UIKit

/*
 * 本节主要内容:
 * 1.分析错误处理的三个阶段
 * 2.三个阶段整合
 */

/* 目的: 针对不同错误情况, 反映不同的错误信息
 * 1.错误描述: 一般枚举类型, 遵循协议Error
 * 2.错误抛出: throw / throws
 * 3.错误捕获(处理): do / try / catch
 */

// 阶段一: 错误描述
// 描述"自动贩卖机器"枚举类型(错误信息)
enum VendingMachineError: Error {
    case InvalidSelection
    case NotEnoughMoney(coinNeeded: Int)
    case OutOfStock
    // .......
}

// 阶段二: 错误抛出(函数定义/声明); exception
func canThrowError(name: String?) throws -> String {
    guard name != nil else {
        print("There is no such product.")
        // 以前: return "no such"
        throw VendingMachineError.InvalidSelection
    }
    return "You can buy it!"
}

// 阶段三: 错误捕获/处理
// 原来: var result = canThrowError(name: "Water")
// 较严格/完整的方式
do {
    var result = try canThrowError(name: nil)
} catch {
    print("Invalid Selection")
}

// 三个阶段结合样例
// 描述贩卖机器结构体
struct VendingMachine {
    // 描述商品的结构体
    struct Item {
        // 描述商品类型枚举
        enum ItemType: String {
            case Water // "Water"
            case Cola // "Cola"
            case Juice // "Juice"
        }
        let type: ItemType
        // 价格
        let price: Int
        // 个数
        var count: Int
    }
    
    // 第一阶段: 错误描述
    enum ItemError: Error {
        case NoSuchItem // 没有改产品
        case NotEnoughMoney(Int) // 返回不够的钱数
        case OutOfStock // 卖完了
    }
    
    // 声明存储属性(字典)
    var items = ["Mineral Water": Item(type: .Water, price: 5, count: 15), "Coca Cola": Item(type: .Cola, price: 7, count: 10), "Orange Juice": Item(type: .Juice, price: 10, count: 20)]
    
    // 阶段二: 错误抛出     //mutating 只是表示可以在方法内部修改 结构体或者枚举的变量
    mutating func vend(itemName: String, money: Int) throws -> Int {
        guard var item = items[itemName] else {
            throw ItemError.NoSuchItem
        }
        // 返回真正产品的价格
        guard money >= item.price else {
            throw ItemError.NotEnoughMoney(item.price)
        }
        guard item.count > 0 else {
            throw ItemError.OutOfStock
        }
        
        item.count -= 1
        
        // 找回钱数
        return money - item.price
    }
}

// 第三阶段: 错误处理
var machine = VendingMachine()
var pocketMoney = 15
// 方式一: 强制执行有throw方法; 
// 风险: 如果有错误, 无法处理; 编译错误
pocketMoney = try! machine.vend(itemName: "Coca Cola", money: pocketMoney)

// 方式二: 尝试着执行有throw方法
// 缺点和优势: 如果有错误, 无法处理; 但是不会有编译错误
try? machine.vend(itemName: "Cola", money: pocketMoney)

// 方式三: do / try / catch
do {
    pocketMoney = try machine.vend(itemName: "Cola", money: pocketMoney)
} catch VendingMachine.ItemError.NoSuchItem {
    print("No such product.")
} catch VendingMachine.ItemError.NotEnoughMoney {
    print("Not enough money.")
} catch VendingMachine.ItemError.OutOfStock {
    print("Out of stock")
} catch {
    print("Error.....")
}



import UIKit

// 课堂练习

struct Matrix {
    // 声明行数和列数存储属性
    let rows: Int, columns: Int
    // 声明一维数组属性
    var grid: [Double]
    
    // init构造方法
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        let defaultValue = Double(self.rows) * Double(self.columns)
        grid = Array(repeating: defaultValue, count: rows * columns)
    }
    
    // 判定参数有效性
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    
    subscript(row: Int, column: Int) -> Double {
        get {
            // 使用assert断言, 判断传入参数的有效性
            assert(indexIsValid(row: row, column: column), "Index is out of range.")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index is out of range.")
            grid[(row * columns) + column] = newValue
        }
    }
}

// 实例化
var matrix = Matrix(rows: 3, columns: 4)
// 获取第1行第2列数据
matrix[1, 2]
// 对第1行第1列赋值
matrix[1, 1] = 1000
// 验证越界情况, 显示assert断言错误信息
// matrix[3, 4]


Day05

回顾:
1. 枚举类型: 值类型; 自定义类型(声明 + 实例化)
   1.1 基本语法:
       enum EnumName {
      case caseName1
      case caseName2
    }
  1.2 rawValue: 元值; 声明阶段关联类型, 每个case默认有关联值(rawValue) —> case的值都是常量
       enum EnumName: Int {
      case caseName1 // 0
      case caseName2 // 1
    }
   —> rawValue可以自定义值, 要求如下:
      a. 值必须唯一
           b. 只能关联: Int / Float / Double / String / Character
   1.3 associated value: 关联值; 声明阶段每个case关联类型, 实例化阶段, 给关联的类型赋值. —> case的值都是变量
       enum Shape {
      case Square(side: Double)
      case Rectangle(width: Double, height: Double)
      case Circle(centerX: Double, centerY: Double, radius: Double)
      case Point // 没有默认的值
    }
   // 实例化
   var square = Shape.Square(side: 10)
      var squareNew = Shape.Square(side: 20)
2. 结构体: 声明 + 实例化 + 添加属性和方法(自定义)
   struct StructName {
       var latitude: Double
       var longitude: Double
       mutating func functionName() {
            latitude += 1.0 // 修改结构体的属性
       }
   }
   var structInstance =  StructName(latitude: 10.21, longitude: 11.432)
  structInstance.latitude

今天内容:
	·	 结构体中init构造方法
	·	 subscript语法(下标语法)
	·	 类

结构体中init构造方法
1. 引言: Int / Float / Double / String / Array / Dictionary都是结构体, 点语法获取属性/方法.
   —> var imInt = Int(10) var imFloat = Float(10.5)
2. 样例: 为结构体添加init构造方法
    [ 01_struct ]
    —> 总结:
      a. 默认init构造方法
      b. 自定义init构造方法

/05_Swift/Day05/Day05-AM1.zip

3. 样例: 为结构体添加可失败的构造方法init?
    [ 02_init_struct ]

4. 样例: 为结构体添加两种类型的属性(语法同样适用于类)
    [ 03_property_subscript ]
    —> 属性分类:
      a.  存储型属性Stored Property: 存储值
   b. 计算型属性Computed Property: set/get方法
   —> 下标语法subscript
      a. 例如: array[0], array[1], dictionary[0], structName[x]
   —> 总结:
       a. 计算型属性更加灵活, 更加直接

/05_Swift/Day05/Day05-AM2.zip

———————— 下午内容 ———————
1. 继续Demo03中的下标语法
   —> 下标语法注意事项:
     a. 针对对象: 枚举/结构体/类
     b. 作用: 使用下标语法设置/获取属性的值
     c. 语法: 函数和计算型属性结合

/05_Swift/Day05/Day05-PM1.zip

2. Error Handling(重点和难点)
  2.1 例如: 没有任何错误信息提示
  2.2 例如: 字符串转成整型  Int(“hello”) -> nil(最直接/最简单的错误信息)
  2.3 Error Handling错误处理机制: 面向终端用户以及程序员机制, 显示错误原因信息; 
  2.4 样例: 实现错误处理机制
        [ 04_error_handling ]

/05_Swift/Day05/Day05-PM2.zip


 课堂练习: 
 [ 05_practice ]
 1).需求: 声明一个描述二维数组的结构体Matric, 使用下标语法, 通过两个下标(行,列)访问一维数组的元素
 2).要求: init构造方法(初始化一维数组), init方法的参数两个(行数和列数); 处理越界情况
 3).结果: matric[1, 5] -> 获取二维数组的第1行第5列元素
 

Day05知识点总结:
1. 掌握结构体可失败构造函数本质和语法
2. 掌握结构体存储型属性和计算性属性语法和适用场景
3. 理解下标subscript语法
4. 掌握三种错误处理的方式



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值