下面简单的介绍协议部分的应用
协议基础
协议和构造函数
为什么使用协议
类型别名(typealias)和光联类型(associated type)
标准库中常用的协议
protocol Pet{
//: 协议里面的属性,只能说明是可读还是可写
// 对于属性,不能有初始值
var name: String{ get set }// = "My Pet"
// 统一使用var关键字
var birthPlace: String{ get }
// 对于属性,get,set隐藏了实现细节,可以使用let实现只读,也可以使用只有get的计算型属性
//注意:协议里面的方法只写协议的申明,不写协议的实现方法,这是协议里面方法的特殊地方,而这个方法是怎么实现的,有遵守这个协议的类和机构来管理的
// 对于方法,不能有实现
func playWith()
// 对于方法,不能有默认参数(默认参数就是一种实现)
//func fed(food: String = "leftover")
func fed()
func fed(food: String)
// 可以使用mutating关键字,强调这个方法应该修改其内容
mutating func changeName(newName:String)
// 不可以设置访问控制
// 协议就是协议,如果开发者可以看见协议,就可以看见协议里的任何内容
}
// 不能实例化Pet
//var pet = Pet()
// 协议的继承
protocol PetBird: Pet{
var flySpeed: Double{ get }
var flyHeight: Double{ get }
}
// 协议的实现,实现协议规定的所有属性和方法即可
struct Dog: Pet{
// 可以使用计算型属性
// private var myDoggyName = "Puppy"
// var name: String{
// get{
// return myDoggyName
// }
// set{
// myDoggyName = newValue
// }
// }
var name: String
// protocol的read-only,对一个具体类的实现,不一定只读,但是作为Pet是只读的!
//let birthPlace: String
var birthPlace: String
func playWith() {
print("Wong!")
}
func fed(){
print("I want a bone.")
}
// 在具体实现上可以加默认参数
func fed(food: String = "Bone"){
if food == "Bone"{
print("Happy")
}
else{
print("I want a bone")
}
}
// 对于class,不需要mutating关键字
mutating func changeName(newName: String) {
name = newName
}
}
let myDog:Dog = Dog(name: "summer", birthPlace: "beijing")
// 从Pet的角度看,myDog的birthPlace是只读的!
let aPet: Pet = myDog
//aPet.birthPlace = "shanghai"
protocol Pet{
var name: String{ get set }
init(name: String)
func playWith()
func fed()
}
class Animal{
var type: String = "mammal"
}
// 如果一个类有继承的类,则父类必须放在前面
class Dog: Animal, Pet{
// 如果protocol没有init(name)的要求,name有默认名字就够了
var name: String = "Puppy"
// 如果protocol有init,则在class中必须注明required
required init(name: String){
self.name = name
}
func playWith() {
print("Wong")
}
func fed(){
print("I love bones")
}
}
final class Cat: Animal, Pet{
var name: String = "Kitten"
// 如果是final class, init可以没有required, 因为也不会再被继承了
init(name: String){
self.name = name
}
func playWith() {
print("Meow")
}
func fed(){
print("I love fish")
}
}
class Bird: Animal{
var name: String = "Little Little Bird"
init(name: String){
self.name = name
}
}
// 如果只是继承Bird,Bird的init为required,则override可以省略
// 否则,必须有override, 可以没有required
// 因为有Pet,则required也不能省
class Parrot: Bird, Pet{
required override init(name: String){
super.init( name: name + " " + name )
}
func playWith() {
print("Hello")
}
func fed(){
print("Thank you!")
}
}
protocol Pet{
var name: String {get set}
}
protocol Flyable{
var flySpeed: Double {get}
var flyHeight: Double {get}
}
class Animal{
}
class Dog: Animal, Pet{
var name = "Puppy"
}
class Cat: Animal, Pet{
var name = "Kitten"
}
class Bird: Animal, Flyable{
var flySpeed: Double
var flyHeight: Double
init(flySpeed: Double, flyHeight: Double){
self.flySpeed = flySpeed
self.flyHeight = flyHeight
}
}
class Parrot: Bird, Pet{
var name: String
init(name: String, flySpeed: Double, flyHeight: Double){
self.name = name + " " + name
super.init(flySpeed: flySpeed, flyHeight: flyHeight)
}
}
class Sparrow: Bird{
var color = UIColor.grayColor()
}
class Vehicle{
}
class Plane: Vehicle, Flyable{
var model: String
var flySpeed: Double
var flyHeight: Double
init(model: String, flySpeed: Double, flyHeight: Double){
self.model = model
self.flySpeed = flySpeed
self.flyHeight = flyHeight
}
}
var dog = Dog()
var cat = Cat()
var parrot = Parrot(name: "hi", flySpeed: 10.0, flyHeight: 100.0)
let pets: [Pet] = [dog, cat, parrot]
for pet in pets{
print(pet.name)
}
var sparrow = Sparrow(flySpeed: 15.0, flyHeight: 80.0)
var plane = Plane(model: "Boeing 747", flySpeed: 200.0, flyHeight: 10_000.0)
let flyers: [Flyable] = [parrot, sparrow, plane]
for flyer in flyers{
print("Fly speed: " , flyer.flySpeed , "Fly Height: " , flyer.flyHeight)
}
1.给一般类型起别名(typealias)
//这里就是给double起了一个别名
typealias Length = Double
extension Double{
//计算型属性可以直接用return返回就是
var km: Length{ return self * 1000.0 }
var m: Length{ return self }
var cm: Length{ return self / 100 }
var ft: Length{ return self / 3.28084 }
}
let runningDistance: Length = 3.54.km//标准库的扩展直接这样写就是,调用方法也一样
runningDistance
typealias AudioSample = UInt64
2.在协议里面给一个类型其别名()(associated type)
// 新版本中,在Protocol中声明,用associatedtype
protocol WeightCalculable {
associatedtype WeightType//首先在协议里面给WeightType起一个别名,但是不给别名赋值,直到真正用到的时候,再给别名赋值
var weight: WeightType { get }
}
// 在具体实现中,用typealias
class iPhone7: WeightCalculable{//遵守了协议就要实现协议里面的方法和属性
typealias WeightType = Double//在用到别名的时候再给别名赋值,但是注意协议里的别名关键字是associatedtype,而结构和类中关键字为typealias
var weight: WeightType{
return 0.114
}
}
class Ship: WeightCalculable{
typealias WeightType = Int
var weight: WeightType
init(weight: Int){
self.weight = weight
}
}
extension Int{//这里其实就是int增添一个计算型属性,如果一个数.t,那么就是返回一千倍
typealias Weight = Int
var t: Weight{return 1_000*self}
}
let titanic = Ship(weight: 46_328_000)
let good = Ship(weight: 46_328.t)
// Equatable, Comparable,协议
// Equatable and comparable
struct Record: Equatable, Comparable{
//Equatable协议是对“==”运算符进行重载,Comparable协议是对所有比较运算符重载,这里只需要最“<”运算符进行重载就是
var wins: Int
var losses: Int
}
// 必须紧跟着写,不能在中间插入任何语句
func ==(left: Record, right: Record) -> Bool{
return left.wins == right.wins && left.losses == right.losses
}
func <(left: Record, right: Record) -> Bool{
if left.wins != right.wins{
return left.wins < right.wins
}
return left.losses > right.losses
}
let recordA = Record(wins: 10, losses: 5)
let recordB = Record(wins: 10, losses: 5)
recordA == recordB
// 不仅仅是重载 == 的意义在于,告诉别人,我是Equatable的!
var team1Record = Record(wins: 10, losses: 3)
var team2Record = Record(wins: 8, losses: 5)
var team3Record = Record(wins: 8, losses: 8)
var records = [team1Record,team2Record,team3Record]
records.sort()
//CustomStringConvertible, BooleanType协议
// CustomStringConvertible:可以有自定义打印格式。 and BooleanType
struct Record: Equatable, Comparable, CustomStringConvertible, BooleanType{
var wins: Int
var losses: Int
var description: String{
return "WINS: " + String(wins) + " , LOSSES: " + String(losses)
}
var boolValue: Bool{
return wins > losses
}
}
func ==(left: Record, right: Record) -> Bool{
return left.wins == right.wins && left.losses == right.losses
}
func <(left: Record, right: Record) -> Bool{
if left.wins != right.wins{
return left.wins < right.wins
}
return left.losses > right.losses
}
let record = Record(wins: 10, losses: 5)
print( record )
if record{
print("Great!")
}
// 可以在extension中实现协议!
// 局限:不能使用存储型变量
extension Int: BooleanType{
public var boolValue: Bool{
return self != 0
}
}
var wins = 0
if !wins{
print("You never win!")
}
//以后出现ble后缀的协议,意思就是这个协议描述的是什么特性,type结尾的协议描述的是可以成为什么类型