美文网首页
Swift 基础(0) - 协议、枚举 、异常

Swift 基础(0) - 协议、枚举 、异常

作者: 静持大师 | 来源:发表于2017-03-26 20:56 被阅读33次

    面向协议

    • 面向对象的问题: 不能实现多继承,且会导致继承关系变得复杂
    • 面向协议的事例:
    protocol SportProtocol {
        var hot: Double  {get set} // {get set}表示可读可写
        
        func playFootBall()
        @objc optional func playBasketBall() // 前面的 @objc optional 表示方法是可选的
    }
    
    // 在协议中, 属性/方法可以在 extension 中默认实现
    extension SportProtocol {
        var price: Double { // 此时属性只读, 想要修改, 必须覆盖
            return 100.0
        }
        
        func playFootBall() {
            print("T足球")
        }
    }
    
    • 实现统一加载 nib的 协议
    import Foundation
    import UIKit
    
    protocol NibLoadProtocol {
        
    }
    
    // where Self: UIView 表示调动的必须是 UIView 及其子类
    extension NibLoadProtocol where Self: UIView {
        // 协议中 static 表示类方法
        static func loadFromNib() -> Self {
            return Bundle.main.loadNibNamed("\(self)", owner: nil, options: nil)?.first as! Self
        }
    }
    

    枚举

    • 枚举的语法,enum开头,每一行成员的定义使用case关键字开头,一行可以定义多个关键字
    enum CompassPoint {
        case North
        case South
        case East
        case West
    }
     
    enum CompassPoint {
        case North, South, East, West
    }
    
    上例中North,South,East,West的值并不等于0,1,2,3,而是他们本身就是自己的值,且该值的类型就是CompassPoint
    
    var directionToHead = CompassPoint.West 
    // directionToHead是一个CompassPoint类型,可以被赋值为该类型的其他值
    // 当设置directionToHead的值时,他的类型是已知的,因此可以省略East的类型
    directionToHead = .East
    
    • 使用switch分开枚举的值,以进行的不同的操作。switch内的case必须包含枚举的所有分支,否则编译出错。当然,列举所有枚举值不太方便时,可以使用default
    directionToHead = .South
    switch directionToHead {
    case .North:
        println("Lots of planets have a north")
    case .South:
        println("Watch out for penguins")
    case .East:
        println("Where the sun rises")
    case .West:
        println("Where the skies are blue")
    }
    
    • 枚举的元素可以是结合值(associated value),下面通过一个可以存储一维条形码(由3个整数组成)和二维条形码(由字符串组成)的枚举条形码实例来说明
    enum Barcode {
        case UPCA(Int, Int, Int)
        case QRCode(String)
    }
    // 定义一个变量。该变量即可被赋值为3个整数,又可被赋值为一个字符串,但都是Barcode类型的枚举值
    var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
    productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
     
    // 使用switch时,case内可区分条形码种类,可使用变量或常量获得结合值
    switch productBarcode {
    case .UPCA(let numberSystem, let identifier, let check):
        println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
    case .QRCode(let productCode):
        println("QR code with value of \(productCode).")
    }
    // 打印 "QR code with value of ABCDEFGHIJKLMNOP."
    
    *在case内部,如果其类型都为let或var,则该关键字可提前到case和枚举类型中间,如:
    case let .UPCA(numberSystem, identifier, check):
    
    • 原始值类型的枚举在枚举名后紧跟数据类型,其枚举的成员在定义时已经赋予了初始值,且不能改变,与结合值类型的枚举相比,结合值是在将枚举值赋予一个变量时,才设置了那个枚举的值。
    //原始值枚举的类型紧跟枚举名后,其成员的原始值的数据类型都是这个指定的类型
    enum ASCIIControlCharacter: Character {
        case Tab = "\t"
        case LineFeed = "\n"
        case CarriageReturn = "\r"
    }
    //Int类型的原始值枚举成员的原始值是递增的,比如Venus的值是2,Earth的值是3
    enum Planet: Int {
        case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
    }
    //可以通过toRaw方法获得枚举成员的原始值
    let earthsOrder = Planet.Earth.toRaw()
    // earthsOrder 的值是 3,数据类型是Int
     
    //可以通过fromRaw方法获得原始值对应的枚举成员
    let possiblePlanet = Planet.fromRaw(7)
    // possiblePlanet 的数据类型 Planet? 值是 Planet.Uranus
     
    //因为fromRaw的原始值可能没有对应的枚举成员,所以返回的类型是一个可选变量值
    let positionToFind = 9
    if let somePlanet = Planet.fromRaw(positionToFind) {
        switch somePlanet {
        case .Earth:
            println("Mostly harmless")
        default:
            println("Not a safe place for humans")
        }
    } else {
        println("There isn't a planet at position \(positionToFind)")
    }
    // 枚举定义中没有原始值为9的成员,所以打印 "There isn't a planet at position 9"
    
    

    枚举函数

    //枚举函数
    enum mobileLanguageFun{
         case IOS (String, String)
         case Android (String)
         //定义枚举函数
         var description: String{
             switch self {
                 case  mobileLanguageFun.IOS(let language1, let language2):
                     return "language1 = \(language1), language2 = \(language2)"
                     
                 case mobileLanguageFun.Android(let temp):
                     return temp
                 default:
                     return ("NO")
             }
     
         }
     }
     
     var myMobile: mobileLanguageFun = mobileLanguageFun.IOS("objc", "swift")
     println(myMobile.description)  //language1 = objc, language2 = swift
    

    错误处理与异常抛出

    主动退出程序的几种情况

    • Fatal Errors(致命的错误)
      • 使用fatalError()函数可以立即终止你的应用程序,在fatalError()中可以给出终止信息。使用fatalError()函数,会毫无条件的终止你的应用程序,用起来也是比较简单的,就是一个函数的调用。
    fatalError("致命错误,调用我程序终止")
    
    • Assertions(断言)
      • 在断言中的提示条件是可选的。断言会在Debug模式下起作用,但是在Release版本中就会被忽略。
    // @param: condition, 为true时,断言不执行,相应的断言信息不打印。为false时,断言执行,并且打印相应的断言信息。
    assert(<#T##condition: Bool##Bool#>, <#T##message: String##String#>)
    
    • 先决条件(Preconditions)
      • Preconditions的用法和断言一样,不过有一点需要主要,Preconditions在debug和release模式下都会被执行,除非使用–Ounchecked进行编译。
    precondition(<#T##condition: Bool##Bool#>, <#T##message: String##String#>)
    

    Swift中的错误处理

    • 在Swift中,如果你要定义你自己的错误类型,你只需要实现ErrorType协议即可。声明完错误类型后,就可以在处理错误抛出异常时使用自定义的错误类型了。

    1.使用枚举创建错误类型

    • 1.1遵循ErrorType协议,自定义错误类型。下方定义了一个错误类型枚举,该枚举遵循了ErrorType协议,在接下来的代码中我们将会使用这个MyCustomErrorType枚举
    // 定义错误类型
    enum MyErrorType: ErrorType {
        case ErrorReason1
        case ErrorReason2
        case ErrorReason3
    }
    
    • 1.2在我们的函数定义时可以使用throws关键字,以及在函数中使用throw关键字对错误进行抛出,抛出的错误类型就可以使用上面我们自己定义的错误类型。
    func throwError() throws {
            let test: Int? = nil
            
            guard test != nil else {
                throw MyErrorType.ErrorReason2
            }
        }
    
    • 1.3上面函数的功能是对错误进行抛出,接下来就该使用do-catch来处理抛出的错误。使用try对错误进行捕捉,使用do-catch对错误进行处理。
            do {
                try throwError()
            } catch MyErrorType.ErrorReason1 {
                print("错误原因: 1")
            }catch MyErrorType.ErrorReason2 {
                print("错误原因: 2")
            }catch {
                print("错误原因: 3")
            }
    

    2.使用结构体为错误处理添加Reason

    • 使用结构体来遵循ErrorType协议, 可以在抛出错误时,给自定义错误类型提供错误原因。
    • 2.1使用结构体创建错误类型,下方名为MyErrorType的结构体遵循了ErrorType协议,并且在MyErrorType结构体中,声明了一个reason常量,该reason常量中存储的就是错误原因
    struct MyErrorType2: ErrorType {
        let reason1: String
        let reason2: String
    }
    
    • 2.2上面定义完错误类型结构体后,在错误抛出中就可以使用了。在错误抛出时,可以传入一个错误原因
    func throwError2() throws {
            let test: Int? = nil
            
            guard test != nil else {
                throw MyErrorType2(reason1: "原因1", reason2: "原因2")
            }
        }
    
    • 2.3最后要对抛出的错误进行do-catch处理,在处理时,可以对错误原因进行打印,错误原因存储在error中
            do {
                try throwError2()
            } catch {
                print(error)
            }
    

    3.使String类型遵循ErrorType协议,直接使用String提供错误原因

    • 这种方式最为简单
    extension String: ErrorType {
        
    }
    
    func throwError3() throws {
        let test: Int? = nil
        
        guard test != nil else {
            throw "error"
        }
    }
    
    do {
        try throwError3()
    } catch {
        print(error)
    }
    

    相关文章

      网友评论

          本文标题:Swift 基础(0) - 协议、枚举 、异常

          本文链接:https://www.haomeiwen.com/subject/sbkkottx.html