Swift基础语法简化版(续)

2020年12月29日 阅读数:54
这篇文章主要向大家介绍Swift基础语法简化版(续),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

闭包
javascript


首先来看一段示例:
php

//计算一个数的平方
//函数写法func square(a : Int) -> Int { return a * a}square(a: 6)
//闭包写法let sq = { (a : Int) -> Int in return a * a}sq(6)


闭包的写法模式:
java

let 闭包名 = {    函数类型 in    须要执行的代码块}


闭包可以捕获和存储定义在其上下文中的任何常量和变量,即闭合并包裹那些常量和变量,所以被称为“闭包”。nginx

闭包是能够被传递和引用的一个独立模块编程


闭包跟函数同样,也是引用类型
swift


闭包表达式
数组


闭包表达式的语法有以下的通常形式:ruby

{    (参数罗列) -> (返回值类型) in    须要执行的代码语句}

说明以下:
微信

1,闭包表达式由一对花括号 {} 开始与结束闭包

2,由 in 关键字将闭包分割成两部分:参数与返回值(能够理解成函数的类型)闭包体

3,闭包中的参数不一样于函数中的参数的一点是,闭包中的参数不能提供默认值,而函数中的参数能够提供默认值。其余都是同样的。


闭包的简写


首先咱们来看一个例子,从一个数组中筛选出合适的数据组成新的数组:

//首先定义一个函数,函数有两个参数,第一个参数是须要筛选的数组,第二个参数是筛选条件函数func getNewList(scores : [Int], checkMethod : (Int)->Bool) -> [Int] {    var newList = [Int]()    for num in scores {        if checkMethod(num) {            newList.append(num)        }    }    return newList}
//函数是一种特殊的闭包,因此上面的筛选条件函数能够写成以下闭包形式let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {(numInt : Int) -> Bool in return numInt > 80})print(newList) // [86, 98, 100]


let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {(numInt : Int) -> Bool in return numInt > 80})

上面的这行代码,是闭包的完整写法。下面来看一些简写的写法。


第一层简写:省略掉闭包类型中的 -> 与 返回值类型 ,由于根据后面的表达式能够推断出返回值是一个Bool

let newList = getNewList(scores: [55, 60, 71, 86, 98, 100], checkMethod: {(numInt : Int) in return numInt > 80})


第二层简写:省略掉参数的类型和小括号,由于参数的类型能够根据定义闭包时的函数类型进行推断

let newList = getNewList(scores: [5560718698100], checkMethod: {numInt in return numInt > 80})


第三层简写:省略掉 return 关键字,在单行闭包的时候,return关键字能够省略

let newList = getNewList(scores: [5560718698100], checkMethod: {numInt in numInt > 80})


第四层简写:省略掉参数的声明和 in 关键字,使用参数名称缩写$0

let newList = getNewList(scores: [5560718698100], checkMethod: {$0 > 80})

Swift 提供了参数名称的缩写功能,直接经过$0、$一、$2来顺序调用闭包的参数


最多见的闭包类型——尾随闭包


尾随闭包是最多见的一种闭包类型。


尾随闭包是一个在函数调用的时候,书写在函数括号以后的闭包表达式。当函数中最后一个参数是闭包表达式的时候,在调用该函数的时候,就能够将做为最后一个参数的闭包表达式写成尾随闭包


func getNewList(scores : [Int], checkMethod : (Int)->Bool) -> [Int] {    var newScoreList = [Int]()    for score in scores {        if checkMethod(score) {            newScoreList.append(score)        }    }    return newScoreList}
//调用函数的时候,不使用尾随闭包getNewList(scores: [41,62,83], checkMethod: { (score : Int) -> Bool in return score > 60})
//调用函数的时候,使用尾随闭包getNewList(scores: [41, 62, 83]) { (score) -> Bool in return score > 60}


枚举



枚举的定义


C和OC中,枚举成员在被建立的时候会被赋予一个默认的整数值,枚举的本质就是一组整型值。


而在Swift中,枚举是更加灵活的,第一,你没必要给每个枚举成员提供一个值;第二,若是须要给枚举成员提供值,那么能够提供的值类型包括字符、字符串、整型值、浮点值等。


定义方式一:

enum CompassPoint {    case East    case West    case North    case South}

这里的 case 关键词代表新的一行成员值将被定义。

与C/OC不一样的一点是,Swift的枚举成员在被建立的时候不会被赋予一个默认的整数值。好比上面的这个例子中,EastWestNorthSouth不是隐式的等于0、一、二、3。


定义方式二:

enum CompassPoint {    case East, West, North, South}

枚举的多个成员值能够出如今同一行上,此时只须要只用一个case 关键词便可。


枚举的赋值


枚举类型赋值能够是字符、字符串、整型、浮点型。


若是要给枚举类型赋值,则必需要在枚举类型后面明确说明值的具体类型

enum CompassPoint : Int{    case East = 1    case West = 2    case North = 3    case South = 4}
enum CompassPoint : Double{ case East = 1.0 case West = 2.0 case North = 3.0 case South = 4.0}
enum CompassPoint : String{ case East = "East" case West = "West" case North = "North" case South = "South"}


枚举的类型推断


首先给变量赋一个枚举值:

enum CompassPoint : String{    case East = "East"    case West = "West"    case North = "North"    case South = "South"}
var a = CompassPoint.Eastprint(a) // East


而后对该变量进行穷举:

switch a {case CompassPoint.East:    print("东")case CompassPoint.West:    print("西")case CompassPoint.North:    print("北")case CompassPoint.South:    print("南")}


上面的这个穷举能够简写为以下(将枚举类型移除):

switch a {case .East:    print("东")case .West:    print("西")case .North:    print("北")case .South:    print("南")}


之因此能够将枚举类型给简化掉,是由于根据上下文,系统能够检测到变量a 匹配的值是 CompassPoint 这个枚举类型下面的值。这就是Swift中的枚举类型推断


枚举的原始值


在C/OC中,枚举的本质就是整数。因此C/OC的枚举是有原始值的,而且默认是从0开始。

Swift中的枚举是没有原始值的,可是能够在定义的时候告诉系统让枚举有原始值。


关于设置Swift中枚举的原始值,须要注意如下几点:

  1. 若是原始值是String类型,则原始值是区分大小写的

  2. 经过 rawValue 能够获取原始值

  3. 经过 rawValue 返回的枚举是一个可选型,由于原始值对应的枚举值不必定存在

  4. 若是想指定第一个元素的原始值以后,后面的元素的原始值可以默认+1,则枚举必定是Int类型


enum CompassPoint : Int {    case East = 1    case West    case North    case South}
let a = CompassPoint.Northprint(a) // Northprint(a.rawValue) // 3

这个例子中,枚举的原始值设置的是Int类型,而且设置了第一个枚举值的原始值是1,因此North的原始值就是3。


enum CompassPoint : Int {    case East = 1    case West    case North    case South}
//经过原始值来获取对应的枚举值//这里获取的枚举值是一个可选型,由于原始值对应的枚举值不必定存在let b = CompassPoint(rawValue: 4)let c = CompassPoint(rawValue: 5)


结构体


结构体(struct)是由一系列具备相同类型或者不一样类型的数据构成的数据集合。

结构体既能够定义属性(变量、常量),也能够定义方法(函数)。

Swift中的结构体是值类型


结构体的定义语法


struct 结构体名称 {    // 属性和方法}


举例以下:

struct Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}

该例中,定义了一个名叫Person的结构体。这个结构体拥有三个属性(nameagegentle)和一个方法(singASong)。


结构体实例


实例化结构体的方式一:

实例化结构体最简单的方式就是在结构体名字后面加上(),此时,任何属性都被初始化为默认值。

struct Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}
let person1 = Person()print("我叫\(person1.name),我今年\(person1.age)岁,性别\(person1.gentle)")//打印结果:我叫norman,我今年18岁,性别man


实例化结构体的方式二:

全部的结构体都会有一个自动生成的成员构造函数来实例化结构体,可使用它来初始化全部的成员属性。

struct Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}
let person2 = Person(name: "Lavie", age: 20, gentle: "male")print("我叫\(person2.name),我今年\(person2.age)岁,性别\(person2.gentle)")//打印结果:我叫Lavie,我今年20岁,性别male


访问结构体实例的属性和方法


咱们可使用点语法来访问一个结构体实例的属性和方法。以下:

struct Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}
let person1 = Person()print("我叫\(person1.name),我今年\(person1.age)岁,性别\(person1.gentle)") // 我叫norman,我今年18岁,性别manperson1.singASong() // 《海阔天空》


若是点语法是在等号后面,或者没有等号,那么就是访问;若是点语法在等号前面,就是赋值。以下:

struct Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}
var person1 = Person()print("我叫\(person1.name)") // 我叫normanperson1.name = "lavie" // 赋值print("我叫\(person1.name)") // 我叫lavieperson1.singASong() // 《海阔天空》


结构体是值类型


值类型是一种当它被赋值给一个常量或者变量,或者被传递给函数时,会被拷贝的类型。


Swift中的枚举、结构体等都是值类型,它在代码传递中老是会被拷贝


struct Person {    var name = "norman"}
var person1 = Person()// 值类型拷贝var person2 = person1
//此时改变person2,并不会改变person1的值person2.name = "lavie"
print(person1.name) // normanprint(person2.name) // lavie


Swift中的字符串String、字典Dictionary、数组Array类型,是做为结构体来实现的,这意味着,当String、Dictionary、Array类型的实例被赋值到一个新的常量或者变量,或被传递到一个函数中的时候,其实传递的是拷贝后的值


OC中的NSString、NSArray和NSDictionary,他们是做为类来实现的,因此NSString、NSArray和NSDictionary的实例对象老是做为一个引用,而不是拷贝来实现赋值和传递。




Swift虽然推荐是面向协议编程,但其也是一门面向对象的语言。

面向对象的语言中很重要的两个概念是:类和对象。对象是类的实例。

Swift中用class关键字来定义类。


定义语法


class 类名 {     // 定义属性和方法}


举例:

class Person {    var name = "norman"    var age = 20        func play() {        print("play")    }}

该例中定义了一个名为Person的类,该类有两个属性和一个方法。


类的实例


 类的实例化与结构体的实例化同样,最简单的就是在名称后面加一个小括号(),可是类默认没有成员构造函数。


var person = Person()


访问属性和方法


类属性方法的访问和结构体的属性方法的访问是如出一辙的。


咱们可使用点语法来访问一个类的实例的属性和方法。以下:

class Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}
let person1 = Person()print("我叫\(person1.name),我今年\(person1.age)岁,性别\(person1.gentle)") // 我叫norman,我今年18岁,性别manperson1.singASong() // 《海阔天空》


若是点语法是在等号后面,或者没有等号,那么就是访问;若是点语法在等号前面,就是赋值。以下:

class Person {    var name = "norman"    var age = 18    var gentle = "man"    func singASong() {        print("《海阔天空》")    }}
var person1 = Person()print("我叫\(person1.name)") // 我叫normanperson1.name = "lavie" // 赋值print("我叫\(person1.name)") // 我叫lavieperson1.singASong() // 《海阔天空》


类是引用类型


与值类型不一样,引用类型被赋值到一个常量或者变量,或者被传递到一个函数中的时候,它是不会被拷贝的,而是使用的同一个对某实例的引用。


class Person {    var name = "norman"}
var person1 = Person()// 引用类型var person2 = person1
//此时改变person2,会影响person1的值,由于它俩引用的是同一个对象person2.name = "lavie"
print(person1.name) // lavieprint(person2.name) // lavie


特征运算符


因为类是引用类型,可能有不少常量或者变量都是引用到了同一个类的实例。有时候须要找出两个常量或者变量是否引用自同一个实例,Swift中提供了两个特征运算符来检查两个常量或者变量是否引用自相同的实例

  • ===       引用自类的同一个实例

  • !==        没有引用自类的同一个实例


class Person {    var name = "norman"}
var person1 = Person()var person2 = person1var person3 = Person()
// 特征运算符print(person1 === person2) // trueprint(person2 === person3) // false


继承


一个类是能够从另一个类那继承方法、属性和其余的特性的。

当一个类从另一个类那里继承的时候,继承的类就是子类,被继承的类就是父类。

继承的目的是为了代码复用。


//父类class Person {    var name = "norman"    func eat() {        print("eat")    }}
//子类class Child : Person { var school = "杭州市第一小学"}
//子类class Adult : Person { var company = "杭州魔筷"}
var person = Person()var child = Child()var adult = Adult()
//Child和Adult都继承了其父类Person的方法person.eat()child.eat()adult.eat()


重写(覆写)


所谓重写,就是子类能够对继承自父类的实例方法、类型方法、实例属性、类型属性进行覆盖。

重写须要在前面加上override关键字。

override关键字执行的时候,Swift编译器会检查重写的类的父类(或者父类的父类)是否有与之匹配的声明来提供重写。


//父类class Person {    var name = "norman"    func eat() {        print("eat")    }}
//子类class Child : Person { var school = "杭州市第一小学" //重写父类的方法 override func eat() { print("child eat") }}
//子类class Adult : Person { var company = "杭州魔筷" //重写父类的方法 override func eat() { print("adult eat") }}
var person = Person()var child = Child()var adult = Adult()
person.eat() // eatchild.eat() // child eatadult.eat() // adult eat


若是不想父类的属性或者方法被重写,那么能够经过final关键字来阻止子类的重写行为:

//父类class Person {    var name = "norman"    //经过final关键字阻止被重写    final func eat() {        print("eat")    }}
//子类class Child : Person { var school = "杭州市第一小学" //重写父类的方法 // 此时会报错error: instance method overrides a 'final' instance method override func eat() { print("child eat") }}


与结构体均可以用来定义自定义的数据类型,结构体实例老是经过值来传递,而类实例老是经过引用来传递


类的属性介绍


在Swift的类中,属性分为以下三种:

  • 存储属性:用于存储类的实例的常量和变量

  • 计算属性:经过某种方式计算出来的属性

  • 类属性:与整个类自身相关的属性


1、存储属性


存储属性是最简单的属性,它做为类实例的一部分,用于存储常量和变量

咱们能够给存储属性提供一个默认值,也能够在初始化方法中对其进行初始化。


class Student {    var name : String?    var age : Int = 19        var chineseScore : Double = 0.0    var mathScore : Double = 0.0}
//建立实例对象var student = Student()
//给存储属性赋值student.name = "norman"student.age = 18
student.chineseScore = 98.0student.mathScore = 96.0

本例中的nameage都是存储属性,用来记录该学生的姓名和年龄。

chineseScoremathScore也是存储属性,用来记录该学生的语文分数和数学分数。


2、计算属性


计算属性并不存储实际的值,而是提供一个getter和一个可选的setter来间接获取和设置其属性值。


计算属性通常只提供getter方法,不提供setter方法。


若是只提供getter方法,而不提供setter方法的话,则该计算属性为只读属性,而且能够省略掉get{}


class Student {    //存储属性    var name : String?    var age : Int = 19        var chineseScore : Double = 0.0    var mathScore : Double = 0.0        //计算属性    var averageScore : Double {        get {            return (chineseScore + mathScore)/2        }    }    }
//建立实例对象var student = Student()
//给存储属性赋值student.name = "norman"student.age = 18
student.chineseScore = 98.0student.mathScore = 96.0
//获取计算属性student.averageScore // 97

本例中,averageScore是计算属性,它的值是由chineseScoremathScore计算得来。

须要注意的是,averageScore的定义以下:

    //计算属性    var averageScore : Double {        get {            return (chineseScore + mathScore)/2        }    }

能够简化为:

    //计算属性    var averageScore : Double {        return (chineseScore + mathScore)/2    }


3、类属性


类属性是与类相关联的,而不是与类的实例相关联。


全部的类和实例都共有一份类属性,所以在某一处修改以后,该类属性就会被修改。


类属性的设置和修改须要经过类来完成


下面是类属性的写法:

class Student {    //存储属性    var name : String?    var age : Int = 19        var chineseScore : Double = 0.0    var mathScore : Double = 0.0        //计算属性    var averageScore : Double {        return (chineseScore + mathScore)/2    }        //类属性    static var courseCount : Int = 3}
//建立实例对象var student = Student()
//给存储属性赋值student.name = "norman"student.age = 18
student.chineseScore = 98.0student.mathScore = 96.0
//获取计算属性student.averageScore // 97
//类属性的设值与取值Student.courseCount = 6print(Student.courseCount) // 6


4、懒加载属性


懒加载属性是指第一次被调用的时候才会计算其初始值的属性,也就是说,懒加载的对象在第一次使用的时候才会真正被加载到内存中。


在OC中,咱们经过gettter方法来实现懒加载。

可是在Swift中,咱们是在属性的声明前使用lazy关键字来表示该属性是延迟加载(即懒加载)的。


class Student {    //懒加载属性    //在第一次使用到该属性的时候,执行闭包,将闭包的返回值赋值给属性    lazy var terchers: [String] = {        () -> [String] in        return ["tercher1", "tercher2", "tercher3"]    }()}
//建立实例对象var student = Student()
print(student.terchers) // ["tercher1", "tercher2", "tercher3"]


协议


协议的定义


协议的定义方式与类、结构体、枚举的定义方式很是类似:

protocol SomeProtocol {    //属性    //方法}


协议中的属性须要遵循如下几点:

  • 必须设置为变量var

  • 不能够有默认值

  • 必须设置是{get}仍是{get set},{get}表示只读,{get set}表示可读可写


协议中的方法须要注意如下几点:

  • 方法不能有方法体

  • 方法中的参数不能有默认值


protocol SomeProtocol {    //属性    var name : String {get set}        //方法    func play(company : String)    mutating func eat()}


协议的遵循


遵循协议的写法跟继承父类的写法实际上是同样的:

//协议protocol SomeProtocol {    //属性    var name : String {get set}        //方法    func play(company : String)    mutating func eat()}
//父类class Person { var age : Int = 18}
//遵循协议,继承父类class Student : Person, SomeProtocol {    //实现协议中的属性 var name: String = ""     //实现协议中的方法 func play(company: String) { print("play with \(company)") } func eat() { print("to dine") }}


协议的继承


//父协议protocol ParentProtocol {    //属性    var name : String {get set}        //方法    func play(company : String)    mutating func eat()}
//子协议protocol SonProtocol : ParentProtocol { func study()}
//遵循协议class Student : SonProtocol { //实现父协议中的内容 var name: String = "" func play(company: String) { print("play with \(company)") } func eat() { print("to dine") } //实现子协议中的内容 func study() { print("study") }}


协议中方法的可选


1,optional关键字


@objc protocol ParentProtocol {        func play(company : String)    //该方法可选    @objc optional func eat()}
//遵循协议class Student : ParentProtocol { //实现协议中的内容 //此时能够不实现协议中的可选方法,固然也能够实现 func play(company: String) { print("play with \(company)") }}


2,扩展协议


protocol ParentProtocol {    func play(company : String)    func eat()}
extension ParentProtocol { //能够在协议的拓展中对协议中的方法进行默认的实现 func eat() { print("eat") }}
//遵循协议class Student : ParentProtocol { //实现协议中的内容 //若是协议中的方法已经在拓展中默认实现了,这里能够实现也能够不实现 func play(company: String) { print("play with \(company)") }}


咱们能够利用协议的扩展,对协议中的一些方法进行默认实现。若是在协议的扩展中对某些方法进行了实现,那么在遵循协议的类里面,能够不实现已经有了默认实现的方法。


协议的运用——代理模式


//第1步,定义一个协议,规定须要完成的任务protocol BuyTicketProtocol {    func buyTicket()}
//第2步,让具体的类或者结构体来实现协议,将任务具体化class Assistant : BuyTicketProtocol { func buyTicket() { print("秘书去买票") }}
class Scalpers : BuyTicketProtocol { func buyTicket() { print("黄牛去买票") }}
//第3步,委托方的一个配置class Person { //3.1,首先设置代理属性 var delegate : BuyTicketProtocol? func goToShanghai() { print("准备去上海,找我的去买票") //3.2,在须要完成任务的时候经过代理来进行操做 delegate?.buyTicket() print("买到票了,准备出发") }}
//第4步,设置委托方的代理var person = Person()person.delegate = Scalpers() // 设置委托方的代理person.goToShanghai()


打印结果为:

准备去上海,找我的去买票

黄牛去买票

买到票了,准备出发



扩展


扩展能够为类、结构体、枚举、协议添加新的功能。Swift中的扩展相似于OC中的分类。


扩展能够作的事情:

  • 添加计算属性

  • 定义方法

  • 使现有类型遵循某种协议


在Swift中,使用extension关键字来实现扩展。


其语法以下:

extension SomeType {    // 这里的SomeType能够是类、枚举、结构体,也能够是协议    // 在这里面去添加一些新的内容}


扩展计算属性


扩展能够在不动原有类型的状况下,向已有的类型添加计算实例属性和计算类型属性。


extension Int {    //给Int类型增长一个平方属性    var square: Int {        return self * self    }}
var a = 2print(a.square) // 4


Int是结构体,上例演示了经过扩展给一个结构体增长计算实例属性。


扩展方法


扩展一个普通方法

extension Int {    func square() -> Int {        return self * self    }}
var a = 8print(a.square()) // 64


使现有类型遵循某协议


扩展可使既有类型遵循一个或者多个协议,协议的遵循书写方式与原类中彻底一致。语法以下:

extension SomeClass : SomeProtocol, AnotherProtocol {    //能够用于分离原类中的代码}

这个写法在开发中是很是有用的,好比能够将tableView、collectionView的代理从原控制器中给抽离出来,避免臃肿。


泛型


所谓泛型,顾名思义,就是普遍类型。也就是说,一开始不肯定是什么类型,等到真正使用的时候,根据赋值的数据类型来肯定类型。


先来看个案例,好比如今咱们须要交换两个Int类型的变量的值,实现以下:

//交换传入的两个数的值func SwapTwoInts(a : inout Int, b : inout Int) {    let temp = a    a = b    b = temp}
var lilyAge = 20var normanAge = 26SwapTwoInts(a: &lilyAge, b: &normanAge)print(lilyAge) // 26print(normanAge) // 20


我如今又增长了一个需求,就是既须要转换Int类型的两个数值,也须要转换Double类型的两个数值,或者是转换其余类型的两个数值,那怎么办呢?,这些方法仅仅是参数的类型不一样,是否是针对每个类型都须要写一个转换方法呢?


此时就须要用到泛型了。

//泛型函数func SwapTwoValues<T>(a : inout T, b : inout T) {    let temp = a    a = b    b = temp}
var lilyAge = 20var normanAge = 26SwapTwoValues(a: &lilyAge, b: &normanAge)print(lilyAge) // 26print(normanAge) // 20
var lilyName = "lily"var normanName = "norman"SwapTwoValues(a: &lilyName, b: &normanName)print(lilyName) // normanprint(normanName) // lily


该例中的 T 是一个类型参数(它能够是任意名称,咱们通常使用 T 来表示),类型参数用于指定并命名一个占位符类型,并使用<>包裹,放在函数名后边,好比该例中的<T>可使用它来指定参数类型或者返回值的类型在真正调用的时候会被实际的类型替代,如传递的是Int,就替换为Int;若是传递的是Double,就替换为Double等等。


泛型的类型约束


有时候咱们须要给泛型作一些约束,好比必须继承自某个父类,或者必须遵循某些协议等,这也是能够作到的。语法以下:

func someFunction<T : SomeClass, U : SomeProtocol>(someT : T, someU : U) {}


协议里面的泛型——关联类型


上面所说的是在类或者结构体、枚举中使用泛型,在协议中是不能够这样使用的。协议中使用泛型,是经过 associatedtype 关键字。


protocol SomeProtocol {    associatedtype Element        func play(parameter1 : Element, parameter2 : Element)}
struct SomeStruct : SomeProtocol { func play(parameter1: String, parameter2: String) { print("play, \(parameter1), \(parameter2)") }}
var s = SomeStruct()s.play(parameter1: "666", parameter2: "norman")


说明以下:

  • 协议中的泛型,是经过关键字 associatedtype 来实现的

  • 与类、结构体或者枚举中的泛型同样,协议中的泛型也能够进行类型约束(经过继承或者遵循协议的方式)


面向协议编程


众所周知,Swift是一门面向协议编程的语言。我所理解的面向协议编程是这样的:针对某个须要实现的功能,可使用协议定义出接口,而后利用协议的拓展为其提供默认的实现。若是在某地方须要这个功能,则只须要声明遵循该协议便可。遵照某个协议的对象调用协议中声明的方法时,若是遵循者本省没有提供方法的实现,那么协议扩展提供的默认实现将会被调用


//定义一个协议protocol WatchMovieProtocol {    func watchAMovie(name : String)}
//遵循协议并实现协议中的方法class Student : WatchMovieProtocol { func watchAMovie(name: String) { print("去电影院看《\(name)》") }}


上例中是一个遵循者遵循该协议,若是此时有100个遵循者都须要遵循该协议,而且该协议方法的实现都是同样的,那么是否须要在每个遵循者里面都实现一下协议方法呢?


固然不须要,咱们可使用协议的拓展为协议中的方法提供一个默认实现:

//定义一个协议protocol WatchMovieProtocol {    func watchAMovie(name : String)}
//利用协议的拓展,给协议中的方法提供默认实现extension WatchMovieProtocol { func watchAMovie(name : String) { print("去电影院看《\(name)》") }}
//遵循协议class Student : WatchMovieProtocol {}
var studet = Student()studet.watchAMovie(name: "燃情岁月")

打印以下:

去电影院看《燃情岁月》


若是某一个遵循者须要独特的实现,那么咱们本身再实现一个协议便可:

//定义一个协议protocol WatchMovieProtocol {    func watchAMovie(name : String)}
//利用协议的拓展,给协议中的方法提供默认实现extension WatchMovieProtocol { func watchAMovie(name : String) { print("去电影院看《\(name)》") }}
//遵循协议,而且自定义协议方法的实现class Student : WatchMovieProtocol { func watchAMovie(name : String) { print("学生去电影院看《\(name)》") }}
var studet = Student()studet.watchAMovie(name: "燃情岁月")

打印以下:

学生去电影院看《燃情岁月》


本文分享自微信公众号 - iOS小生活(iOSHappyLife)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

上一篇: c语言递归练习
下一篇: D# 语法