Learn Swift - Section 4th 扩展、协议、泛型

扩展 Extension


扩展Extension就是向一个已有的类、结构体、枚举类型或者协议类型添加新功能(functionality)。这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模)。扩展和 Objective-C 中的分类(categories)类似。(不过与 Objective-C 不同的是,Swift 的扩展没有名字。)

Swift 中的扩展可以:

  • 添加计算型属性和计算型静态属性
  • 定义实例方法和类型方法
  • 提供新的构造器
  • 定义下标
  • 定义和使用新的嵌套类型
  • 使一个已有类型符合某个协议
  • 也可以对一个协议进行扩展
  extension Int{
    //转换成小时
    var hours : Int{
        return self/3600
    }
    var ago : Int{
        return -self
    }
    //x之前的时间
    func ago(x:Int) -> Int {
        return self - x
    }
}

let currentTime = 7200
3.hours
3.hours.ago
3.ago + currentTime
//5秒之前
currentTime.ago(5)
//1小时之前
currentTime.hours.ago(1)
currentTime.hours.ago(3600.hours)
print(3.ago)

协议 Protocol


协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性。类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。任意能够满足协议要求的类型被称为遵循(conform)这个协议。

除了遵循协议的类型必须实现那些指定的规定以外,还可以对协议进行扩展,实现一些特殊的规定或者一些附加的功能,使得遵循的类型能够收益。

protocol SellProducts{
    func sellProducts(product:String)
}

class Person {
    var name:String
    weak var delegate:Seller?
    lazy var someClosure:(Int,String)->String = {
        //在闭包中将self修饰为无主引用。将delegate 修饰为 弱引用
        [unowned self,weak delegate = self.delegate!]//捕获列表
        (index:Int,strToProcess:String)->String in

        return "\(self.name),\(self.delegate),\(delegate)"
    }
    init(name:String,delegate:Seller?){
        self.name = name;
        self.delegate = delegate;
    }

    func giveSellerProducts(product:String ) -> Bool {

        self.delegate?.sellProducts(product)
        return true
    }
}

class Seller : SellProducts{
    var product:String?
    func sellProducts( product: String) {
        self.product = product
    }
}
let seller = Seller()
var person = Person (name: "Hanliu", delegate: seller)

//刚开始seller是没有商品的,要等到Person给seller
print(seller.product)
//person告诉seller,帮我卖苹果
person.giveSellerProducts("apple")
//现在seller手中就有了商品了
print(seller.product!)

person.someClosure(1,"haha")

协议中的属性一定要指明读写状态

protocol SomeProtocol {
    var mustBeSettable:Int{get set}//表示该属性是可读可写
    var notNeededForSetable:String{get}//表示只读

    static var someTypedProperty:String{get set}//类属性(当协议遵循者是class是,可以用class关键字)

}
protocol FullyName {
    var fullname:String{get}
}
struct PersonName:FullyName {
    var fullname: String
    var shortName :String
}

let person = PersonName(fullname: "Levi John",shortName: "LJ")
person.fullname

协议本身并不实现任何功能,但是协议可以被作为类型使用。就是与String、Int这些类型的作用相同。

  • 作为函数、方法或构造器中的参数类型或返回值类型
  • 作为常量、变量或属性的类型
  • 作为数组、字典或其他容器中的元素的类型
protocol RandomGenerator {
    func random()->Double
}
class LinerGenerator:RandomGenerator {
    func random() -> Double {
        return 11.0011
    }
}
class Dice{
    let slides:Int
    var generator:RandomGenerator//作为属性类型
    init(slides:Int,generator:RandomGenerator){//作为参数类型
        self.slides = slides
        self.generator = generator
    }

    func roll() -> Int {
        return Int(self.generator.random() * Double(slides))+1
    }
}

在扩展中遵循协议,增加协议成员(这种方法与直接在类后面遵循协议的效果相同)。

protocol TextRepresentable {
    var textDescription :String{get}
}

extension Dice:TextRepresentable{
    var textDescription:String {
        return "\(slides) - slides"
    }
}

let dice = Dice(slides: 8, generator: LinerGenerator())
dice.textDescription//现在Dice的所有实例都可以使用textDescription属性了。

协议类型的集合

let sir  = Dice(slides: 1, generator: LinerGenerator())
let sime = Dice(slides: 2, generator: LinerGenerator())

let arrayOfProtocolElements:[TextRepresentable] = [dice,sir,sime]
for element in arrayOfProtocolElements{
    print(element.textDescription)
}

协议能够继承.

protocol TextGo:TextRepresentable{
    var prettyTextDescription:String{get}
}

extension Dice:TextGo{
    var prettyTextDescription:String{
        return textDescription + "hello"//可以使用上层协议的属性
    }
}

类专属协议.在协议继承列表中的首位添加class关键字,然后这个协议就只能被类遵循,而不能被结构体或者枚举遵循。

protocol ClassOnlyProtocol:class{
    var mylove:String{get}
}

检查协议一致性
使用isas?as!

协议本身也可以被扩展

extension TextRepresentable{//TextRepresentable是个协议
    var longTextDescription:String{
        return "\(textDescription) + long"
    }
}

为协议扩展添加限制条件 where
扩展CollectionType协议,让其遵循者的元素必须遵循TextRepresentable协议

extension CollectionType where Generator.Element:TextRepresentable{
    var textDescription:String{
        let items = self.map{$0.textDescription}
            return "A hamster named \(items)"
    }
}

struct Hamster {
    var name: String
    var textDescription: String {
        return "a hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {}//让Hamster遵循TextRepresentable协议

let murrayTheHamster = Hamster(name: "Murray")
let morganTheHamster = Hamster(name: "Morgan")
let mauriceTheHamster = Hamster(name: "Maurice")
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]

因为Array遵循了`CollectionType`协议,而hamster又遵循了`TextRepresentable`协议,所以就满足了条件,此时 array可以使用`textDescription`属性
print(hamsters.textDescription)

结果:A hamster named ["a hamster named Murray", "a hamster named Morgan", "a hamster named Maurice"]

泛型 Generics

泛型代码可以让你写出根据自我需求定义、适用于任何类型的,灵活且可重用的函数和类型。它的可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图。

泛型是 Swift 强大特征中的其中一个,许多 Swift 标准库是通过泛型代码构建出来的。事实上,泛型的使用贯穿了整本语言手册,只是你没有发现而已。例如,Swift 的数组和字典类型都是泛型集。你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。同样的,你也可以创建存储任何指定类型的字典(dictionary),而且这些类型可以是没有限制的

泛型函数

func swapTwoValues(inout a:T,inout b:T){
    let tempValue = a
    a = b
    b = tempValue
}
  • T 表示一个占位命名类型
  • 尖括号表示它里面的T是由函数swapTwoValues定义的一个类型,swift不会去查找命名为T的实际类型
  • 参数列表中的T没有实际类型,仅表示两个参数的类型需要相同

实现一个泛型版本的栈

struct Stack{
    var items = [T]()
    mutating func push(item:T){
        items.append(item)
    }
    mutating func pop(){
        items.removeLast()
    }
}
//泛型实例的创建,都必须指定T的类型
var stack = Stack(items: [""])
var stack2 = Stack()

//扩展一个泛型类型:添加一个属性

extension Stack{
    var topItem:T?{
        return items.isEmpty ? nil : items[items.count - 1]
    }
}

stack2.topItem

关联类型(Associated Type)


swift2.2貌似修改了。声明的时候用associatedtype 实现的时候用typealias

protocol Container{
    associatedtype ItemType
    var count:Int{get}
    mutating func append(item:ItemType)
    subscript (i:Int)->ItemType{get}
}

//让泛型Stack遵循Container协议
extension Stack:Container{
    //typealias ItemType = T //这一行也是可以去掉,因为swift通过类型推断可以判断出T的类型
    mutating func append(item: T) {
        return  self.push(item)//或者:items.append(item)
    }

    var count:Int{
        return items.count
    }
    subscript(i:Int)->T{
        return items[i]
    }
}

你可能感兴趣的:(Learn Swift - Section 4th 扩展、协议、泛型)