扩展 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}
}
检查协议一致性
使用is
、as?
、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]
}
}