swift 协议的使用方法和场景

协议是swift一个重要的部分,类似于Java中的接口,但是还不是很一样。相比较OC,swift中协议更加灵活,它可以应用在很多场景,使整个项目的框架结构更加易于延展。

一、什么场景下使用协议

协议与类类似,可以被继承,当继承某个协议之后就要给协议所定义的属性赋值并且实现协议中的方法。

既然协议与类这么类似,那我们为什么不全部用类来实现,为什么还要用到协议?
举个简单的例子,有一只猫和狗,他们都属于宠物,用类去实现就要这样操作,定义一个父类叫做宠物,里面有喂食和玩耍两个方法,猫和狗都继承与宠物这个父类。这样操作自然可以实现,但是要知道,猫和狗不都是宠物,这里把宠物定义成父类就不是很合适,这里应该把宠物定义成协议就相对合适很多啦

二、协议的使用方法

1、协议定义

// 协议定义通过关键字protocol
protocol SomeProtocol {
    // 协议定义
}

// 协议可以继承一个或者多个协议
protocol SomeProtocol2 :SomeProtocol {
    // 协议定义
}

// 结构体实现协议
struct SomeStructure : SomeProtocol,SomeProtocol2 {
    // 结构体定义
}

// 类实现协议和继承父类,协议一般都写在父类后面
class SomeSuperclass {
    // 父类定义
}

class SomeClass :SomeSuperclass,SomeProtocol,SomeProtocol2 {
    // 子类定义
}

2、协议的属性

协议不指定是否该属性应该是一个存储属性或者计算属性,它只指定所需的属性名称和读写类型。属性要求总是声明为变量属性,用var关键字做前缀。

protocol ClassProtocol {
    static var present:Bool { get set }    // 要求该属性可读可写,并且是静态的
    var subject :String { get }            // 要求该属性可读
    var stname :String { get set }         // 要求该属性可读可写
}

// 定义类来实现协议
class MyClass :ClassProtocol {
    static var present = false       // 如果没有实现协议的属性要求,会直接报错
    var subject = "Swift Protocols"  // 该属性设置为可读可写,也是满足协议要求的
    var stname = "Class"

    func attendance() -> String {
        return "The \(self.stname) has secured 99% attendance"
    }

    func markSScured() -> String {
        return "\(self.stname) has \(self.subject)"
    }
}

// 创建对象
var classa = MyClass()
print(classa.attendance())     // 结果:The Class has secured 99% attendance
print(classa.markSScured())    // 结果:Class has Swift Protocols

3、协议普通方法实现

协议可以要求指定实例方法和类型方法被一致的类型实现。这些方法被写为协议定义的一部分,跟普通实例和类型方法完全一样,但是没有大括号或方法体。可变参数是允许的,普通方法也遵循同样的规则,不过不允许给协议方法参数指定默认值。

// 定义协议,指定方法要求
protocol RandomNumberGenerator {
    func random() -> Double    // 实现该协议,需要实现该方法
}

class LinearCongruentialGenerator :RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0

    // 实现协议方法
    func random() -> Double {
        lastRandom = ((lastRandom * a + c) % m)
        return lastRandom / m
    }
}

let generator = LinearCongruentialGenerator()
print("随机数:\(generator.random())")          //结果:随机数: 0.37464991998171
print("另一个随机数:\(generator.random())")     //结果:另一个随机数: 0.729023776863283

4、协议中实现构造函数

协议SomeProtocol中不光可以声明方法/属性/下标,还可以声明构造器,但在Swift中,除了某些特殊情况外,构造器是不被子类继承的,所以SomeClass中虽然能够保证定义了协议要求的构造器,但不能保证SomeClass的子类中也定义了协议要求的构造器。所以我们需要在实现协议要求的构造器时,使用required关键字确保SomeClass的子类必须也得实现这个构造器。

protocol TcpProtocol {
    // 初始化构造器要求
    init(aprot :Int)
}

class TcpClass :TcpProtocol {
    var aprot: Int
    // 实现协议的初始化要求时,必须使用required关键字确保子类必须也得实现这个构造器
    required init(aprot: Int) {
        self.aprot = aprot
    }
}

var tcp = TcpClass(aprot: 20)
print(tcp.aprot)   // return:20

三、 使用实例

开头说的宠物猫和宠物狗的例子,利用协议可以这样实现,声名个动物的父类,然后让猫和狗class都继承与动物class。在定义一个宠物的属性,里面有玩耍和喂食两个方法,让猫和狗都继承与宠物协议,实现代码如下:

protocol Pet {
    func playWith()
    func fed(food : String)

}

class Animal{


    var name : String = ""
    var birthPlace : String = ""

    init(name: String,birthPlace:String) {

        self.name = name
        self.birthPlace = birthPlace
    }
}


class Dog: Animal, Pet{

    func playWith() {

        print("狗狗在玩")
    }

    func fed(food: String) {

        if food == "骨头" {

            print("狗狗Happy")
        }
        else {

            print("狗狗Sad")
        }
    }


}

class Cat: Animal, Pet {

    func playWith() {


        print("猫猫在玩")
    }

    func fed(food: String) {

        if food == "鱼" {

            print("猫猫Happy")
        }
        else {

            print("猫猫Sad")
        }
    }
}


let dog = Dog(name:"狗狗小黑", birthPlace: "北京")

dog.playWith()

dog.fed(food:"骨头")

let cat = Cat(name:"猫猫小白", birthPlace:"上海")

cat.playWith()

cat.fed(food: "鱼")

注意:同时继承父类和协议的时候,父类要写在前面

四、typealias与协议结合的使用

typealias 的作用是给类型进行扩展,它与协议放在一起使用会碰撞出不一样的火花

1、typealias的基本使用

extension Double {

    var km : Length{ return self * 1000.0 }

    var m : Length{ return self }

    var cm : Length{ return self / 100 }


}

这里对Double类型进行扩展

let runDistance:Length = 3.14.km //3140

2、typealias结合协议使用

定义一个协议,代表重量,但是它的类型要根据继承与它的类或结构体来定义,协议代码如下:

protocol WeightCalculable {

    associatedtype WeightType

    var weight:WeightType{get}

}

这里weight属性的类型就抛了出来,便于继承协议的类或结构体来定义

class iPhone7 : WeightCalculable {

    typealias WeightType = Double

    var weight: WeightType {

        return 0.114
    }

}

class Ship : WeightCalculable {

    typealias WeightType = Int

    let weight: WeightType

    init(weight: Int) {

        self.weight = weight
    }


}

这里定义了两个类,一个是iPhone7,一个是Ship,都继承于协议WeightCalculable,但是weight的类型大不相同。
iPhone7的weight属性是Double类型的,Ship的weight属性是Int类型的。

extension Int {

    typealias Weight = Int
    var t:Weight  {
        return 1_000*self
    }


}

let ship = Ship(weight:4_637.t)

最后这段代码,用于扩充Int类型,自定义了t字段来代表吨

五、系统协议的使用

我们还可以继承于系统协议来定义系统方法,这里简单极少介绍三种常用系统协议

1、Equatable协议用于自定义”==”来实现操作

class Person:Equatable , Comparable, CustomStringConvertible {

    var name:String
    var age:Int

    init(name:String,age:Int) {

        self.name = name
        self.age = age
    }

    var description: String {

        return"name: "+name + ",age:" + String(age)
    }

}

func == (left: Person, right: Person) ->Bool{

    return left.name == right.name && left.age == right.age

}

let personA = Person(name:"a",age:9)

let personB = Person(name:"a",age:10)

personA == personB

personA != personB

注意:func == 方法要紧跟协议下面写,否则编译器会报错

2、Comparable协议用于自定义比较符号来使用的

func <(left: Person, right: Person) ->Bool{


        return left.age < right.age

}

let personA = Person(name:"a",age:9)

let personB = Person(name:"a",age:10)

注意,在定义比较符号后,很多方法也会同时修改便于我们使用,例如排序方法

let person1 = Person(name:"a",age:9)

let person2 = Person(name:"a",age:12)

let person3 = Person(name:"a",age:11)

var  arrPerson = [person1,person2,person3]

arrPerson .sort()

//此时arrPerson : [person1,person3,person2]

3、CustomStringConvertible协议用于自定义打印

class Person:Equatable , Comparable, CustomStringConvertible {

    var name:String
    var age:Int

    init(name:String,age:Int) {

        self.name = name
        self.age = age
    }

    var description: String {

        return"name: "+name + ",age:" + String(age)
    }

}

重写description 讲自定义打印格式return出来

print(person1)

//name: a,age:9

协议是swift非常重要的一部分,苹果甚至为了它单独出来——–面向协议编程,利用协议的优点和灵活性可以使整个项目结构更加灵活,拥有更加易于延展的架构。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Swift面向协议编程(Protocol-Oriented Programming,简称POP)是Swift编程语言中的一个重要特性。使用POP的主要场景包括: 1. 代码复用:使用协议可以将某些功能抽象成一个独立的模块,并使多个不同的类或结构体共享该模块的功能。 2. 增强类型安全:Swift是一种类型安全的编程语言,POP进一步提高了类型安全性,因为它强制规定每个类型都必须遵循相应的协议。 3. 扩展性:使用协议可以轻松地向现有类型添加功能。例如,可以通过扩展一个实现了某个协议的类型来实现对该类型的功能扩展。 4. 网络编程:协议可以用于定义网络通信协议,例如TCP、UDP、HTTP等,方便网络编程。 5. 泛型编程:Swift中的泛型编程和POP密切相关。通过将协议作为类型参数传递,可以实现更灵活的泛型编程。 总之,使用POP可以提高代码的可读性、可维护性和可扩展性,同时也可以使代码更加清晰、简洁、易于测试和优化。 ### 回答2: Swift面向协议编程是一种软件开发方法论,它通过协议来定义一组需要实现的属性、方法和功能,实现了代码的模块化和复用,以及降低代码的耦合度。下面介绍一些Swift面向协议编程的使用场景。 1. 标准化和扩展:通过定义协议,可以规范一组对象需要实现的共同属性和方法。这样,不同的对象可以用相同的方式进行处理和操作,提高代码的可读性和维护性。另外,如果需要为已有类型添加新的功能,可以通过扩展协议来实现,而不需要修改原有的类型。 2. 运行时多态:Swift协议支持多继承,一个类型可以遵循多个协议。通过协议,可以实现运行时的多态,将不同的实现绑定到相同的协议类型上。这可以使得代码更加灵活,能够适应不同的场景和需求。 3. 依赖注入和测试驱动开发:面向协议编程可以方便地进行依赖注入,通过将依赖关系抽象为协议,可以在不同的环境中进行替换。这对于测试驱动开发非常有用,可以提高代码的测试性和可测性。 4. UI 组件定制化:通过定义协议,可以将UI组件的定制化能力下放给使用者。例如,定义一个可定制的协议使用者可以实现该协议,来定制按钮的外观、动画等。这种方式可以提高代码的重用性,同时也增加了代码的灵活性。 总之,Swift面向协议编程提供了一种模块化、可扩展和可定制化的开发方式,适用于各种需要代码复用和灵活性的场景,特别是在项目需要多态、依赖注入和定制化的情况下,面向协议编程可以发挥出其优势。 ### 回答3: Swift面向协议编程是一种重要的编程范式,它可以应用于许多不同的场景。以下是几个常见的使用场景: 1. 模块化和组件化:使用协议定义接口和方法,可以实现模块化和组件化的开发方式。不同的组件可以通过实现相同的协议来进行交互,降低了代码的耦合度,增加了代码的可复用性和可维护性。 2. 单元测试:使用协议可以将被测试的类与测试类进行解耦。通过实现相同的协议,可以用一个模拟的类来替代真实的类进行测试,从而更容易编写和执行单元测试。 3. 多继承Swift不支持多继承,但是可以通过协议来实现类似的功能。一个类可以同时遵循多个协议,从而获取不同协议的功能和属性。这种方式可以在不引入类层次的情况下实现代码的复用。 4. 适配不同平台和框架:在跨平台开发和使用不同框架的情况下,使用协议可以更好地适应不同的平台和框架。通过定义统一的协议,不同的平台和框架可以通过实现这个协议来进行交互和兼容。 5. 插件系统:在一些应用程序中,可能希望用户可以编写自己的插件来扩展应用的功能。使用协议可以定义插件接口,插件通过实现这个协议来与应用进行交互和扩展。 总之,Swift面向协议编程广泛应用于软件开发中。它可以提高代码的可复用性、可扩展性和可维护性,同时也能够促进模块化开发和解耦。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值