美文网首页ios
swift-协议扩展

swift-协议扩展

作者: 焉知非鱼 | 来源:发表于2016-03-12 00:53 被阅读3262次

协议的命名遵循 Swift 的标准库, 即协议名以 "Type", "-able", "-ible" 结尾

例如 SequenceType, GeneratorType, CustomStringConvertible, -type 定义行为, -able 定义元素怎样做某事。

protocol  ExerciseType: CustomStringConvertible {
    var name: String  { get }
    var caloriesBurned: Double { get }
    var minutes: Double { get }
}

// 结构体遵守 ErerciseType 协议, 但是也可以有自己的属性和方法, 这也是一种继承和封装
struct EllipticalTrainer: ExerciseType {
    let name = "Elliptical Machine"
    let caloriesBurned: Double
    let minutes: Double
}

struct Treadmill: ExerciseType {
    let name = "Treadmill"
    let caloriesBurned: Double
    let minutes: Double
    let distancesInMiles: Double
}


extension Treadmill {
    var description: String {
        return "Treadmill(\(caloriesBurned) calories and \(distancesInMiles) miles in \(minutes) minutes)"
    }
}


let ellipticalWorkout = EllipticalTrainer(caloriesBurned: 335, minutes: 30)
let runningWorkout    = Treadmill(caloriesBurned: 350, minutes: 25, distancesInMiles: 4.2)

扩展 ExerciseType


有尖括号<>, 表明这是泛型函数, 而占位符类型(placeholder type)要求遵守 ExerciseType 协议


// 函数体中用了两个 ExerciseType 的属性来计算每分钟燃烧的卡路里

func caloriesPerMinutes<Exercise: ExerciseType>(exercise: Exercise) -> Double {
    return exercise.caloriesBurned / exercise.minutes
}
print(caloriesPerMinutes(ellipticalWorkout))
print(caloriesPerMinutes(runningWorkout))

caloriesBurnedPerMinute(_:) 没有一点错误, 但是每当你拥有一个 ExerciseType 的实例, 你必须记住 caloriesBurnedPerMinute(_:) 函数的存在。所以让每一个 ExerciseType 都有一个 caloriesBurnedPerMinute 属性更适合 —— 但是你不想把同样一份实现拷贝进 EllipticalTrainerTreadmill 结构体中(或者你新创建的 ExerciseType 中)

Swift 能扩展协议


扩展 ExerciseType 协议来添加一个属性

协议扩展能添加已经实现的属性和方法, 但是不能为协议添加新的必须要实现的属性和方法

很像你写泛型函数那样, 协议扩展的内部实现只能访问保证存在的其它属性的方法

添加到协议扩展中的属性和方法对于所有遵守该协议的类型来说都是可访问的。

extension ExerciseType {
    var caloriesBurnedPerMinutes: Double {
        return caloriesBurned / minutes
    }

    var description: String {
        return "Exercise(\(name), burned \(caloriesBurned) calories in \(minutes) minutes)"
    }
}

print(ellipticalWorkout.caloriesBurnedPerMinutes)
print(runningWorkout.caloriesBurnedPerMinutes)

协议扩展 -- where 从句


扩展允许你为任意类型添加属性和方法, 不仅仅是你定义过的自定义类型

同样地, 协议扩展允许你给任何协议添加新的方法和属性, 然而, 就像我们上面提到的, 你为协议添加的属性和方法只能使用其它确定会存在的属性和方法。

使用 where 从句来为 SquenceTypes 协议扩展添加元素(Element)类型为指定类型的约束

extension SequenceType where Generator.Element == ExerciseType {
    func totalCaloriesBurned() -> Double {
        var total: Double = 0
        for exercise in self {
            total += exercise.caloriesBurned
        }
        return total
 }
}

协议扩展中的where 从句和泛型中的 where 从句的语法一样。你添加了一个 totalCaloriesBurned() 方法来计算序列所有运动(exercise)的卡路里总数。 在实现中, 你遍历 self 中的每个 exercise, 这是被允许的, 因为 self 就是某种 SequenceType

然后你访问每个元素中的 caloriesBurned 属性, 这是被允许的, 因为 where 从句约束这个序列的方法的元素类型是 ExerciseType

创建一个ExerciseTypes类型的数组, 数组遵守 SequenceType 协议。所以你可以调用你的新的 totalCaloriesBurned() 方法。

let mondayWorkout: [ExerciseType] = [ellipticalWorkout, runningWorkout]
print(mondayWorkout.totalCaloriesBurned())

这个数组能访问 totalCaloriesBurned() 方法, 因为它的元素类型是[ExerciseType], 所以你得到结果为 685.0。 如果你创建了一个 [Int] 类型的数组, 那么 totalCaloriesBurned() 方法是访问不到的。它不会出现在 Xcode 的自动补全中, 即使你手动输入, 程序也会爆出编译错误。因为它满足不了 where 从句要求的数组的元素类型必须为 ExerciseType 的约束。

协议扩展的默认实现


print(ellipticalWorkout)
print(runningWorkout)

当一个协议为它的(某些或全部)属性和方法提供了默认的实现时, 遵守该协议的类型不一定要实现它们。但是它们能选择去实现它们如果默认实现不合适的话。

既然 Treadmill 自身实现了 description , 你应该看见默认的实现只出现在打印 ellpticalWorkout 上了.

相关文章

  • swift-协议扩展

    协议的命名遵循 Swift 的标准库, 即协议名以 "Type", "-able", "-ible" 结尾 例如 ...

  • swift-扩展

    扩展为现有的类、结构体、枚举类型、或协议添加了新功能。这也包括了为无访问权限的源代码扩展类型的能力(即所谓的逆向建...

  • Swift-扩展

  • swift 4.0 协议 协议扩展

    协议 协议扩展

  • swift 扩展和协议的结合

    协议和扩展是可以结合使用的,可以通过扩展使已有的类型采纳某个协议,也可以对现有协议进行扩展。 一、通过扩展采纳协议...

  • Swift-协议

    最近项目使用的是OC,后头看之前用Swift开发的一个项目时,发现很多细节都忘记了??。为了回忆和以后方便查看,现...

  • Swift-协议

    协议 设置协议后有自动补齐,而且是必实现,不然会报错的。 Static、class 为了保证类与结构体都能够使用,...

  • Swift-协议

    一、概览 二、协议的定义和遵守 二、协议的继承和限定类遵守 三、方法参数要求多个协议 四、OC协议兼容 OC中协议...

  • POP-面向协议编程

    什么是面向协议编程? 面向协议 = 协议 + 扩展 + 继承通过协议、扩展做功能划分,降低模块间的耦合,增强代码的...

  • swift中protocol的extension中使用#sele

    协议扩展 不能在上面这样的协议扩展中直接使用#selector,协议扩展对于OC是看不见的。 其中有个报错: @o...

网友评论

本文标题:swift-协议扩展

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