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

<h2 id = "extension">扩展 Extension</h2>
扩展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)

<h2 id = "protocol">协议 Protocol</h2>
协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性。类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。任意能够满足协议要求的类型被称为遵循(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"]

<h2 id = "Generics">泛型 Generics</h2>

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

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

<h3 id = "func">泛型函数</h3>

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

<h3 id = "generic stack">实现一个泛型版本的栈</h3>

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

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

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

stack2.topItem

<h3 id = "associated type">关联类型(Associated Type) </h3>
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]
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容

  • 本章将会介绍 泛型所解决的问题泛型函数类型参数命名类型参数泛型类型扩展一个泛型类型类型约束关联类型泛型 Where...
    寒桥阅读 634评论 0 2
  • 泛型代码可以确保你写出灵活的,可重用的函数和定义出任何你所确定好的需求的类型。你的可以写出避免重复的代码,并且用一...
    iOS_Developer阅读 800评论 0 0
  • 泛型(Generics) 泛型代码允许你定义适用于任何类型的,符合你设置的要求的,灵活且可重用的 函数和类型。泛型...
    果啤阅读 675评论 0 0
  • 136.泛型 泛型代码让你可以写出灵活,可重用的函数和类型,它们可以使用任何类型,受你定义的需求的约束。你可以写出...
    无沣阅读 1,466评论 0 4
  • 有人说:《消愁》的八杯酒分别是指:一杯敬朝阳 一杯敬月光 敬少年 一杯敬故乡 一杯敬远方 敬青年 一杯敬明天 一杯...
    懵芽阅读 2,470评论 0 1