美文网首页
iOS swift 学习(四)

iOS swift 学习(四)

作者: 齐玉婷 | 来源:发表于2020-12-25 18:29 被阅读0次

    Swift 类型转换
    Swift 语言类型转换可以判断实例的类型。也可以用于检测实例类型是否属于其父类或者子类的实例。

    Swift 中类型转换使用 is 和 as 操作符实现,is 用于检测值的类型,as 用于转换类型。

    类型转换也可以用来检查一个类是否实现了某个协议。

    定义一个类层次
    以下定义了三个类:Subjects、Chemistry、Maths,Chemistry 和 Maths 继承了 Subjects。

    代码如下:

    class Subjects {
        var physics: String
        init(physics: String) {
            self.physics = physics
        }
    }
    
    class Chemistry: Subjects {
        var equations: String
        init(physics: String, equations: String) {
            self.equations = equations
            super.init(physics: physics)
        }
    }
    
    class Maths: Subjects {
        var formulae: String
        init(physics: String, formulae: String) {
            self.formulae = formulae
            super.init(physics: physics)
        }
    }
    
    let sa = [
        Chemistry(physics: "固体物理", equations: "赫兹"),
        Maths(physics: "流体动力学", formulae: "千兆赫")]
    
    
    let samplechem = Chemistry(physics: "固体物理", equations: "赫兹")
    print("实例物理学是: \(samplechem.physics)")
    print("实例方程式: \(samplechem.equations)")
    
    
    let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")
    print("实例物理学是: \(samplemaths.physics)")
    print("实例公式是: \(samplemaths.formulae)")
    以上程序执行输出结果为:
    
    实例物理学是: 固体物理
    实例方程式: 赫兹
    实例物理学是: 流体动力学
    实例公式是: 千兆赫
    

    检查类型
    类型转换用于检测实例类型是否属于特定的实例类型。

    你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。

    类型检查使用 is 关键字。

    操作符 is 来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 true,否则返回 false。

    class Subjects {
        var physics: String
        init(physics: String) {
            self.physics = physics
        }
    }
    
    class Chemistry: Subjects {
        var equations: String
        init(physics: String, equations: String) {
            self.equations = equations
            super.init(physics: physics)
        }
    }
    
    class Maths: Subjects {
        var formulae: String
        init(physics: String, formulae: String) {
            self.formulae = formulae
            super.init(physics: physics)
        }
    }
    
    let sa = [
        Chemistry(physics: "固体物理", equations: "赫兹"),
        Maths(physics: "流体动力学", formulae: "千兆赫"),
        Chemistry(physics: "热物理学", equations: "分贝"),
        Maths(physics: "天体物理学", formulae: "兆赫"),
        Maths(physics: "微分方程", formulae: "余弦级数")]
    
    
    let samplechem = Chemistry(physics: "固体物理", equations: "赫兹")
    print("实例物理学是: \(samplechem.physics)")
    print("实例方程式: \(samplechem.equations)")
    
    
    let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")
    print("实例物理学是: \(samplemaths.physics)")
    print("实例公式是: \(samplemaths.formulae)")
    
    var chemCount = 0
    var mathsCount = 0
    for item in sa {
        // 如果是一个 Chemistry 类型的实例,返回 true,相反返回 false。
        if item is Chemistry {
            ++chemCount
        } else if item is Maths {
            ++mathsCount
        }
    }
    
    print("化学科目包含 \(chemCount) 个主题,数学包含 \(mathsCount) 个主题")
    以上程序执行输出结果为:
    
    实例物理学是: 固体物理
    实例方程式: 赫兹
    实例物理学是: 流体动力学
    实例公式是: 千兆赫
    化学科目包含 2 个主题,数学包含 3 个主题
    

    向下转型
    向下转型,用类型转换操作符(as? 或 as!)

    当你不确定向下转型可以成功时,用类型转换的条件形式(as?)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 nil。

    只有你可以确定向下转型一定会成功时,才使用强制形式(as!)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。

    class Subjects {
        var physics: String
        init(physics: String) {
            self.physics = physics
        }
    }
    
    class Chemistry: Subjects {
        var equations: String
        init(physics: String, equations: String) {
            self.equations = equations
            super.init(physics: physics)
        }
    }
    
    class Maths: Subjects {
        var formulae: String
        init(physics: String, formulae: String) {
            self.formulae = formulae
            super.init(physics: physics)
        }
    }
    
    let sa = [
        Chemistry(physics: "固体物理", equations: "赫兹"),
        Maths(physics: "流体动力学", formulae: "千兆赫"),
        Chemistry(physics: "热物理学", equations: "分贝"),
        Maths(physics: "天体物理学", formulae: "兆赫"),
        Maths(physics: "微分方程", formulae: "余弦级数")]
    
    
    let samplechem = Chemistry(physics: "固体物理", equations: "赫兹")
    print("实例物理学是: \(samplechem.physics)")
    print("实例方程式: \(samplechem.equations)")
    
    
    let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")
    print("实例物理学是: \(samplemaths.physics)")
    print("实例公式是: \(samplemaths.formulae)")
    
    var chemCount = 0
    var mathsCount = 0
    
    for item in sa {
        // 类型转换的条件形式
        if let show = item as? Chemistry {
            print("化学主题是: '\(show.physics)', \(show.equations)")
            // 强制形式
        } else if let example = item as? Maths {
            print("数学主题是: '\(example.physics)',  \(example.formulae)")
        }
    }
    以上程序执行输出结果为:
    
    实例物理学是: 固体物理
    实例方程式: 赫兹
    实例物理学是: 流体动力学
    实例公式是: 千兆赫
    化学主题是: '固体物理', 赫兹
    数学主题是: '流体动力学',  千兆赫
    化学主题是: '热物理学', 分贝
    数学主题是: '天体物理学',  兆赫
    数学主题是: '微分方程',  余弦级数
    Any和AnyObject的类型转换
    

    Swift为不确定类型提供了两种特殊类型别名:

    AnyObject可以代表任何class类型的实例。
    Any可以表示任何类型,包括方法类型(function types)。
    注意:
    只有当你明确的需要它的行为和功能时才使用Any和AnyObject。在你的代码里使用你期望的明确的类型总是更好的。

    Any 实例

    class Subjects {
        var physics: String
        init(physics: String) {
            self.physics = physics
        }
    }
    
    class Chemistry: Subjects {
        var equations: String
        init(physics: String, equations: String) {
            self.equations = equations
            super.init(physics: physics)
        }
    }
    
    class Maths: Subjects {
        var formulae: String
        init(physics: String, formulae: String) {
            self.formulae = formulae
            super.init(physics: physics)
        }
    }
    
    let sa = [
        Chemistry(physics: "固体物理", equations: "赫兹"),
        Maths(physics: "流体动力学", formulae: "千兆赫"),
        Chemistry(physics: "热物理学", equations: "分贝"),
        Maths(physics: "天体物理学", formulae: "兆赫"),
        Maths(physics: "微分方程", formulae: "余弦级数")]
    
    
    let samplechem = Chemistry(physics: "固体物理", equations: "赫兹")
    print("实例物理学是: \(samplechem.physics)")
    print("实例方程式: \(samplechem.equations)")
    
    
    let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")
    print("实例物理学是: \(samplemaths.physics)")
    print("实例公式是: \(samplemaths.formulae)")
    
    var chemCount = 0
    var mathsCount = 0
    
    for item in sa {
        // 类型转换的条件形式
        if let show = item as? Chemistry {
            print("化学主题是: '\(show.physics)', \(show.equations)")
            // 强制形式
        } else if let example = item as? Maths {
            print("数学主题是: '\(example.physics)',  \(example.formulae)")
        }
    }
    
    // 可以存储Any类型的数组 exampleany
    var exampleany = [Any]()
    
    exampleany.append(12)
    exampleany.append(3.14159)
    exampleany.append("Any 实例")
    exampleany.append(Chemistry(physics: "固体物理", equations: "兆赫"))
    
    for item2 in exampleany {
        switch item2 {
        case let someInt as Int:
            print("整型值为 \(someInt)")
        case let someDouble as Double where someDouble > 0:
            print("Pi 值为 \(someDouble)")
        case let someString as String:
            print("\(someString)")
        case let phy as Chemistry:
            print("主题 '\(phy.physics)', \(phy.equations)")
        default:
            print("None")
        }
    }
    以上程序执行输出结果为:
    
    实例物理学是: 固体物理
    实例方程式: 赫兹
    实例物理学是: 流体动力学
    实例公式是: 千兆赫
    化学主题是: '固体物理', 赫兹
    数学主题是: '流体动力学',  千兆赫
    化学主题是: '热物理学', 分贝
    数学主题是: '天体物理学',  兆赫
    数学主题是: '微分方程',  余弦级数
    整型值为 12
    Pi 值为 3.14159
    Any 实例
    主题 '固体物理', 兆赫
    

    AnyObject 实例

    class Subjects {
        var physics: String
        init(physics: String) {
            self.physics = physics
        }
    }
    
    class Chemistry: Subjects {
        var equations: String
        init(physics: String, equations: String) {
            self.equations = equations
            super.init(physics: physics)
        }
    }
    
    class Maths: Subjects {
        var formulae: String
        init(physics: String, formulae: String) {
            self.formulae = formulae
            super.init(physics: physics)
        }
    }
    
    // [AnyObject] 类型的数组
    let saprint: [AnyObject] = [
        Chemistry(physics: "固体物理", equations: "赫兹"),
        Maths(physics: "流体动力学", formulae: "千兆赫"),
        Chemistry(physics: "热物理学", equations: "分贝"),
        Maths(physics: "天体物理学", formulae: "兆赫"),
        Maths(physics: "微分方程", formulae: "余弦级数")]
    
    
    let samplechem = Chemistry(physics: "固体物理", equations: "赫兹")
    print("实例物理学是: \(samplechem.physics)")
    print("实例方程式: \(samplechem.equations)")
    
    
    let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")
    print("实例物理学是: \(samplemaths.physics)")
    print("实例公式是: \(samplemaths.formulae)")
    
    var chemCount = 0
    var mathsCount = 0
    
    for item in saprint {
        // 类型转换的条件形式
        if let show = item as? Chemistry {
            print("化学主题是: '\(show.physics)', \(show.equations)")
            // 强制形式
        } else if let example = item as? Maths {
            print("数学主题是: '\(example.physics)',  \(example.formulae)")
        }
    }
    
    var exampleany = [Any]()
    exampleany.append(12)
    exampleany.append(3.14159)
    exampleany.append("Any 实例")
    exampleany.append(Chemistry(physics: "固体物理", equations: "兆赫"))
    
    for item2 in exampleany {
        switch item2 {
        case let someInt as Int:
            print("整型值为 \(someInt)")
        case let someDouble as Double where someDouble > 0:
            print("Pi 值为 \(someDouble)")
        case let someString as String:
            print("\(someString)")
        case let phy as Chemistry:
            print("主题 '\(phy.physics)', \(phy.equations)")
        default:
            print("None")
        }
    }
    以上程序执行输出结果为:
    
    实例物理学是: 固体物理
    实例方程式: 赫兹
    实例物理学是: 流体动力学
    实例公式是: 千兆赫
    化学主题是: '固体物理', 赫兹
    数学主题是: '流体动力学',  千兆赫
    化学主题是: '热物理学', 分贝
    数学主题是: '天体物理学',  兆赫
    数学主题是: '微分方程',  余弦级数
    整型值为 12
    Pi 值为 3.14159
    Any 实例
    主题 '固体物理', 兆赫
    

    在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。

    Swift 扩展
    扩展就是向一个已有的类、结构体或枚举类型添加新功能。

    扩展可以对一个类型添加新的功能,但是不能重写已有的功能。

    Swift 中的扩展可以:

    添加计算型属性和计算型静态属性
    定义实例方法和类型方法
    提供新的构造器
    定义下标
    定义和使用新的嵌套类型
    使一个已有类型符合某个协议
    语法

    扩展声明使用关键字 extension:
    
    extension SomeType {
        // 加到SomeType的新功能写到这里
    }
    

    一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议,语法格式如下:

    extension SomeType: SomeProtocol, AnotherProctocol {
        // 协议实现写到这里
    }
    

    计算型属性
    扩展可以向已有类型添加计算型实例属性和计算型类型属性。

    实例
    下面的例子向 Int 类型添加了 5 个计算型实例属性并扩展其功能:

    extension Int {
       var add: Int {return self + 100 }
       var sub: Int { return self - 10 }
       var mul: Int { return self * 10 }
       var div: Int { return self / 5 }
    }
        
    let addition = 3.add
    print("加法运算后的值:\(addition)")
        
    let subtraction = 120.sub
    print("减法运算后的值:\(subtraction)")
        
    let multiplication = 39.mul
    print("乘法运算后的值:\(multiplication)")
        
    let division = 55.div
    print("除法运算后的值: \(division)")
    
    let mix = 30.add + 34.sub
    print("混合运算结果:\(mix)")
    以上程序执行输出结果为:
    
    加法运算后的值:103
    减法运算后的值:110
    乘法运算后的值:390
    除法运算后的值: 11
    混合运算结果:154
    构造器
    扩展可以向已有类型添加新的构造器。
    
    这可以让你扩展其它类型,将你自己的定制类型作为构造器参数,或者提供该类型的原始实现中没有包含的额外初始化选项。
    
    扩展可以向类中添加新的便利构造器 init(),但是它们不能向类中添加新的指定构造器或析构函数 deinit() 。
    
    struct sum {
        var num1 = 100, num2 = 200
    }
    
    struct diff {
        var no1 = 200, no2 = 100
    }
    
    struct mult {
        var a = sum()
        var b = diff()
    }
    
    
    extension mult {
        init(x: sum, y: diff) {
            _ = x.num1 + x.num2
            _ = y.no1 + y.no2
        }
    }
    
    
    let a = sum(num1: 100, num2: 200)
    let b = diff(no1: 200, no2: 100)
    
    let getMult = mult(x: a, y: b)
    print("getMult sum\(getMult.a.num1, getMult.a.num2)")
    print("getMult diff\(getMult.b.no1, getMult.b.no2)")
    以上程序执行输出结果为:
    
    getMult sum(100, 200)
    getMult diff(200, 100)
    

    方法
    扩展可以向已有类型添加新的实例方法和类型方法。

    下面的例子向Int类型添加一个名为 topics 的新实例方法:

    extension Int {
       func topics(summation: () -> ()) {
          for _ in 0..<self {
             summation() 
          }
       }
    }  
    
    4.topics({
       print("扩展模块内")       
    })    
        
    3.topics({
       print("内型转换模块内")       
    })  
    以上程序执行输出结果为:
    
    扩展模块内
    扩展模块内
    扩展模块内
    扩展模块内
    内型转换模块内
    内型转换模块内
    内型转换模块内
    

    这个topics方法使用了一个() -> ()类型的单参数,表明函数没有参数而且没有返回值。

    定义该扩展之后,你就可以对任意整数调用 topics 方法,实现的功能则是多次执行某任务:

    可变实例方法
    通过扩展添加的实例方法也可以修改该实例本身。

    结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating,正如来自原始实现的修改方法一样。

    实例
    下面的例子向 Swift 的 Double 类型添加了一个新的名为 square 的修改方法,来实现一个原始值的平方计算:

    extension Double {
       mutating func square() {
          let pi = 3.1415
          self = pi * self * self
       }
    }
    
    var Trial1 = 3.3
    Trial1.square()
    print("圆的面积为: \(Trial1)")
    
    
    var Trial2 = 5.8
    Trial2.square()
    print("圆的面积为: \(Trial2)")
    
    
    var Trial3 = 120.3
    Trial3.square()
    print("圆的面积为: \(Trial3)")
    以上程序执行输出结果为:
    
    圆的面积为: 34.210935
    圆的面积为: 105.68006
    圆的面积为: 45464.070735
    

    下标
    扩展可以向一个已有类型添加新下标。

    实例
    以下例子向 Swift 内建类型Int添加了一个整型下标。该下标[n]返回十进制数字

    extension Int {
       subscript(var multtable: Int) -> Int {
          var no1 = 1
          while multtable > 0 {
             no1 *= 10
             --multtable
          }
          return (self / no1) % 10
       }
    }
        
    print(12[0])
    print(7869[1])
    print(786543[2])
    以上程序执行输出结果为:
    
    2
    6
    5
    

    嵌套类型
    扩展可以向已有的类、结构体和枚举添加新的嵌套类型:

    extension Int {
       enum calc
       {
          case add
          case sub
          case mult
          case div
          case anything
       }
    
       var print: calc {
          switch self
          {
             case 0:
                return .add
             case 1:
                return .sub
             case 2:
                return .mult
             case 3:
                return .div
             default:
                return .anything
           }
       }
    }
    
    func result(numb: [Int]) {
       for i in numb {
          switch i.print {
             case .add:
                print(" 10 ")
              case .sub:
                print(" 20 ")
             case .mult:
             print(" 30 ")
             case .div:
             print(" 40 ")
             default:
             print(" 50 ")
    
          }
       }
    }
    
    result([0, 1, 2, 3, 4, 7])
    以上程序执行输出结果为:
    
     10 
     20 
     30 
     40 
     50 
     50 
    

    Swift 协议
    协议规定了用来实现某一特定功能所必需的方法和属性。

    任意能够满足协议要求的类型被称为遵循(conform)这个协议。

    类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。

    语法
    协议的语法格式如下:

    protocol SomeProtocol {
        // 协议内容
    }
    

    要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号,分隔。

    struct SomeStructure: FirstProtocol, AnotherProtocol {
        // 结构体内容
    }
    

    如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。

    class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
        // 类的内容
    }
    

    对属性的规定
    协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的。

    协议中的通常用var来声明变量属性,在类型声明后加上{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示。

    protocol classa {
        
        var marks: Int { get set }
        var result: Bool { get }
        
        func attendance() -> String
        func markssecured() -> String
        
    }
    
    protocol classb: classa {
        
        var present: Bool { get set }
        var subject: String { get set }
        var stname: String { get set }
        
    }
    
    class classc: classb {
        var marks = 96
        let result = true
        var present = false
        var subject = "Swift 协议"
        var stname = "Protocols"
        
        func attendance() -> String {
            return "The \(stname) has secured 99% attendance"
        }
        
        func markssecured() -> String {
            return "\(stname) has scored \(marks)"
        }
    }
    
    let studdet = classc()
    studdet.stname = "Swift"
    studdet.marks = 98
    studdet.markssecured()
    
    print(studdet.marks)
    print(studdet.result)
    print(studdet.present)
    print(studdet.subject)
    print(studdet.stname)
    以上程序执行输出结果为:
    
    98
    true
    false
    Swift 协议
    Swift
    

    对 Mutating 方法的规定
    有时需要在方法中改变它的实例。

    例如,值类型(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值。

    protocol daysofaweek {
        mutating func show()
    }
    
    enum days: daysofaweek {
        case sun, mon, tue, wed, thurs, fri, sat
        mutating func show() {
            switch self {
            case .sun:
                self = .sun
                print("Sunday")
            case .mon:
                self = .mon
                print("Monday")
            case .tue:
                self = .tue
                print("Tuesday")
            case .wed:
                self = .wed
                print("Wednesday")
            case .thurs:
                self = .thurs
                print("Wednesday")
            case .fri:
                self = .fri
                print("Firday")
            case .sat:
                self = .sat
                print("Saturday")
            default:
                print("NO Such Day")
            }
        }
    }
    
    var res = days.wed
    res.show()
    以上程序执行输出结果为:
    
    Wednesday
    

    对构造器的规定
    协议可以要求它的遵循者实现指定的构造器。

    你可以像书写普通的构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体,语法如下:

    protocol SomeProtocol {
       init(someParameter: Int)
    }
    

    实例

    protocol tcpprotocol {
       init(aprot: Int)
    }
    

    协议构造器规定在类中的实现
    你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器。在这两种情况下,你都必须给构造器实现标上"required"修饰符:

    class SomeClass: SomeProtocol {
       required init(someParameter: Int) {
          // 构造器实现
       }
    }
    
    protocol tcpprotocol {
       init(aprot: Int)
    }
    
    class tcpClass: tcpprotocol {
       required init(aprot: Int) {
       }
    }
    

    使用required修饰符可以保证:所有的遵循该协议的子类,同样能为构造器规定提供一个显式的实现或继承实现。

    如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时标示required和override修饰符:

    protocol tcpprotocol {
        init(no1: Int)
    }
    
    class mainClass {
        var no1: Int // 局部变量
        init(no1: Int) {
            self.no1 = no1 // 初始化
        }
    }
    
    class subClass: mainClass, tcpprotocol {
        var no2: Int
        init(no1: Int, no2 : Int) {
            self.no2 = no2
            super.init(no1:no1)
        }
        // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
        required override convenience init(no1: Int)  {
            self.init(no1:no1, no2:0)
        }
    }
    let res = mainClass(no1: 20)
    let show = subClass(no1: 30, no2: 50)
    
    print("res is: \(res.no1)")
    print("res is: \(show.no1)")
    print("res is: \(show.no2)")
    以上程序执行输出结果为:
    
    res is: 20
    res is: 30
    res is: 50
    

    协议类型
    尽管协议本身并不实现任何功能,但是协议可以被当做类型来使用。

    协议可以像其他普通类型一样使用,使用场景:

    作为函数、方法或构造器中的参数类型或返回值类型
    作为常量、变量或属性的类型
    作为数组、字典或其他容器中的元素类型
    实例

    protocol Generator {
        associatedtype members
        func next() -> members?
    }
    
    var items = [10,20,30].makeIterator()
    while let x = items.next() {
        print(x)
    }
    
    for lists in [1,2,3].map( {i in i*5}) {
        print(lists)
    }
    
    print([100,200,300])
    print([1,2,3].map({i in i*10}))
    以上程序执行输出结果为:
    
    10
    20
    30
    5
    10
    15
    [100, 200, 300]
    [10, 20, 30]
    

    在扩展中添加协议成员
    我们可以可以通过扩展来扩充已存在类型( 类,结构体,枚举等)。

    扩展可以为已存在的类型添加属性,方法,下标脚本,协议等成员。

    protocol AgeClasificationProtocol {
       var age: Int { get }
       func agetype() -> String
    }
    
    class Person {
       let firstname: String
       let lastname: String
       var age: Int
       init(firstname: String, lastname: String) {
          self.firstname = firstname
          self.lastname = lastname
          self.age = 10
       }
    }
    
    extension Person : AgeClasificationProtocol {
       func fullname() -> String {
          var c: String
          c = firstname + " " + lastname
          return c
       }
       
       func agetype() -> String {
          switch age {
          case 0...2:
             return "Baby"
          case 2...12:
             return "Child"
          case 13...19:
             return "Teenager"
          case let x where x > 65:
             return "Elderly"
          default:
             return "Normal"
          }
       }
    }
    

    协议的继承
    协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。

    协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:
    protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // 协议定义
    }
    实例

    protocol Classa {
        var no1: Int { get set }
        func calc(sum: Int)
    }
    
    protocol Result {
        func print(target: Classa)
    }
    
    class Student2: Result {
        func print(target: Classa) {
            target.calc(1)
        }
    }
    
    class Classb: Result {
        func print(target: Classa) {
            target.calc(5)
        }
    }
    
    class Student: Classa {
        var no1: Int = 10
        
        func calc(sum: Int) {
            no1 -= sum
            print("学生尝试 \(sum) 次通过")
            
            if no1 <= 0 {
                print("学生缺席考试")
            }
        }
    }
    
    class Player {
        var stmark: Result!
        
        init(stmark: Result) {
            self.stmark = stmark
        }
        
        func print(target: Classa) {
            stmark.print(target)
        }
    }
    
    var marks = Player(stmark: Student2())
    var marksec = Student()
    
    marks.print(marksec)
    marks.print(marksec)
    marks.print(marksec)
    marks.stmark = Classb()
    marks.print(marksec)
    marks.print(marksec)
    marks.print(marksec)
    以上程序执行输出结果为:
    
    学生尝试 1 次通过
    学生尝试 1 次通过
    学生尝试 1 次通过
    学生尝试 5 次通过
    学生尝试 5 次通过
    学生缺席考试
    学生尝试 5 次通过
    学生缺席考试
    

    类专属协议
    你可以在协议的继承列表中,通过添加class关键字,限制协议只能适配到类(class)类型。

    该class关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。格式如下:

    protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
        // 协议定义
    }
    

    实例

    protocol TcpProtocol {
        init(no1: Int)
    }
    
    class MainClass {
        var no1: Int // 局部变量
        init(no1: Int) {
            self.no1 = no1 // 初始化
        }
    }
    
    class SubClass: MainClass, TcpProtocol {
        var no2: Int
        init(no1: Int, no2 : Int) {
            self.no2 = no2
            super.init(no1:no1)
        }
        // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
        required override convenience init(no1: Int)  {
            self.init(no1:no1, no2:0)
        }
    }
    
    let res = MainClass(no1: 20)
    let show = SubClass(no1: 30, no2: 50)
    
    print("res is: \(res.no1)")
    print("res is: \(show.no1)")
    print("res is: \(show.no2)")
    以上程序执行输出结果为:
    
    res is: 20
    res is: 30
    res is: 50
    

    协议合成
    Swift 支持合成多个协议,这在我们需要同时遵循多个协议时非常有用。

    语法格式如下:

    protocol Stname {
        var name: String { get }
    }
    
    protocol Stage {
        var age: Int { get }
    }
    
    struct Person: Stname, Stage {
        var name: String
        var age: Int
    }
    
    func show(celebrator: Stname & Stage) {
        print("\(celebrator.name) is \(celebrator.age) years old")
    }
    
    let studname = Person(name: "Priya", age: 21)
    print(studname)
    
    let stud = Person(name: "Rehan", age: 29)
    print(stud)
    
    let student = Person(name: "Roshan", age: 19)
    print(student)
    以上程序执行输出结果为:
    
    Person(name: "Priya", age: 21)
    Person(name: "Rehan", age: 29)
    Person(name: "Roshan", age: 19)
    

    检验协议的一致性
    你可以使用is和as操作符来检查是否遵循某一协议或强制转化为某一类型。

    is操作符用来检查实例是否遵循了某个协议。
    as?返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil。
    as用以强制向下转型,如果强转失败,会引起运行时错误。
    实例
    下面的例子定义了一个 HasArea 的协议,要求有一个Double类型可读的 area:

    protocol HasArea {
        var area: Double { get }
    }
    
    // 定义了Circle类,都遵循了HasArea协议
    class Circle: HasArea {
        let pi = 3.1415927
        var radius: Double
        var area: Double { return pi * radius * radius }
        init(radius: Double) { self.radius = radius }
    }
    
    // 定义了Country类,都遵循了HasArea协议
    class Country: HasArea {
        var area: Double
        init(area: Double) { self.area = area }
    }
    
    // Animal是一个没有实现HasArea协议的类
    class Animal {
        var legs: Int
        init(legs: Int) { self.legs = legs }
    }
    
    let objects: [AnyObject] = [
        Circle(radius: 2.0),
        Country(area: 243_610),
        Animal(legs: 4)
    ]
    
    for object in objects {
        // 对迭代出的每一个元素进行检查,看它是否遵循了HasArea协议
        if let objectWithArea = object as? HasArea {
            print("面积为 \(objectWithArea.area)")
        } else {
            print("没有面积")
        }
    }
    以上程序执行输出结果为:
    
    面积为 12.5663708
    面积为 243610.0
    没有面积
    

    相关文章

      网友评论

          本文标题:iOS swift 学习(四)

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