swift3.0 protocol 概览——boolan

6 篇文章 0 订阅

一 协议的定义
协议中可以声明属性,方法,初始化器,以及下标等。要注意所有的协议都不能声明析构器(协议不能生成实例,也不会有析构的必要)

import Foundation
//定义协议
protocol Drawable{
    //属性
    var discription:String{
            get
        }
       //方法
        func draw()
        //初始化器
        init()
        //下标
        subscript(index:Int)->Int{
            get
        }
        //系统提示在“==”定义在协议内必须声明为static
        static func == (lhs:Self,rhs:Self)->Bool
}
//协议在java C#里面叫接口 叫interface

二 实现协议
协议在实现过程中,必须要实现protocol中所有声明的属性、函数等。参数需保持一致。
在实现属性时,可以实现计算属性;也可以实现为存储属性。
这里要注意一点,在协议中定的“==”编译要求需要指定为static才让通过编译。在实现该函数时,“==”操作符重载均为全局函数。

class Point:Drawable{
        var x:Int
        var y:Int
        //当定义的类不为final类时,required必须要加,表示子类一定要实现这个函数。参数需一致
         required init() {
            x = 10
            y = 10
        }
    //z在使用时 重载的init函数不算实现协议 必须要有参数一样的函数。
        init(x:Int,y:Int){
            self.x = x
            self.y = y
        }
        var discription: String=""
//这里是说协议中可以将协议中的属性实现为存储属性,或者为计算属性都可以
//    var discription: String{
//        get{
//            return "[\(x),\(y)]"
//        }
//        set{
//            self.discription = newValue
//        }
//    }
    func draw(){
        print(self.discription)
    }
    subscript(index:Int)->Int{
        return 0
    }
}
//子类自动实现父类的实现
class Point3D:Point{
    var z:Int
    required init(){
        z=0
        super.init()//在继承中需要显示调用 另外自己的初始化不能写在后面
    }
}
//“==”虽然为全局函数,但是如果不编写该函数。编译器任然会提示错误。
func == (lhs:Point ,rhs:Point)->Bool{
    if(lhs.x==rhs.x&&lhs.y==rhs.y){
        return true
    }
    else{
    return false
    }
}
var p1=Point(x:100,y:200)
var p2=Point(x:50,y:50)
p1==p2
Point.print_point(lhs: p1)

三使用协议 swift3,0在参数传递中发生了些变化,在协议的使用中也有些许的变化发生。
3.1 mutating
该关键字用来修饰值类型的函数,表示该函数会修改值类型的值。同时协议中对应的该函数也需要声明为mutating。对类来说没有这条要求,协议中的mutating对类没有影响。那么在使用这一条时就注意,如果协议的可能会给让值类型来实现(struct,enum),那么就将需要改变属性的函数声明为mutating,不然编译器会报错

//: [Previous](@previous)
import Foundation
//: [Next](@next)
protocol Shape{
    var discription:String{
        get
    }
    mutating func moveTo(x:Int,_ y:Int)
}
struct Point:Shape{
    var x=10
    var y=20
    //mutating也只能用于修饰值类型的函数,如果用来修饰class 会报错。
     mutating func moveTo(x: Int, _ y: Int) {
        self.x=x
        self.y=y
    }
    var discription: String{
        return "[\(x),\(y)]"
    }

    func display(){
        print(self.discription)
    }
}

3.2关于函数传值与传引用
下面的代码 process(element:Shape)函数调用了 moveTo函数 ,而moveTo会让shape类型的属性发生改变。而我们知道的,swift传参均为传值,且默认声明为let类型(即不可变)。这时编译会报错
“cannot use mutating member on imutable value:’element’ is a ‘let’ constant’”
那按照课程中所述,在参数前声明var可行码? 如下也不可行编译器提示:“parameters may not have the var specifier”。显然swift3.0 已然不支持该参数说明。
总的来说3.0做了优化,因为本身来讲将函数参数声明为var在swift中是没有意义的!如果是引用参数,自然可以变化;但值类型参数的改变,并没有实际意义,不能改变函数外部,只能留在函数体类(将其作为返回值意义不大),有点类似与effective C++中条款,要求将函数参数类型全部设置为const。
在这里如果要改变值类型,这里做法是传引用,主动声明为inout。
func process(element:inout Shape)“实际上在这里传进去的就为外部实例的指针,函数类对参数的改变,会影响到外面值。
同时进行了测试,这个函数传引用类型与值类型均能得到想要的结果。
不论该函数用于值类型还是引用类型,使用时均需使用修饰符 &
(这还真是与C++的引用一德性~~~)


//这样写在这里会报错:cannot use mutating member on immutable value: 'element' is a 'let' constant
//element.moveTo(x:100,200)
//func process(element:Shape){
//    element.moveTo(x:100,200)
//    print(element.discription)
//}

//swift3.0在这里做了优化,不能用视频中的var来修饰函数参数,本身var的函数参数就没有意义。当传值时,如果需要修改传进去的参数,需要用inout来修饰。
//对于class显示声明为inout对结果没影响。这里编译器做的事声明处理呢
//parameters may not have the var specifier
//func process(var element:Shape){
//    element.moveTo(x:100,200)
//    print(element.discription)
//}
func process(element:inout Shape){
    element.moveTo(x:100,200)
    print(element.discription)
}
var pt:Shape
pt = Point()
var pt2:Shape
pt2 = pt
print(pt.discription)
print(pt2.discription)
process(element:&pt)
print(pt.discription)
print(pt2.discription)
pt.moveTo(x:200,300)
print(pt.discription)

3.3以上输出结果为:

[10,20]
[10,20]
[100,200]
[100,200]
[100,200]

四 检查协议类型
这里定义了一个AProtocol协议,一个Base类,Sub类继承了Base并实现了AProtocol协议

//: [Previous](@previous)
import Foundation

protocol AProtocol{
    func display()
}

class Base{
    var no=0
}

class Sub:Base,AProtocol{
    func display() {
        print(no)
    }
}

//Compile-time type 编译时类型 声明类型
var item1,item2:Base
//Runtime Type运行时类型
item1=Base()
item2=Sub()

4.1运行时类型识别
is标示符来进行运行时识别,返回一个boolean值。如下所示:item2 is AProtocol;该标示符是针对类型的识别item2 is Sub这样写也是没问题的。
编译时类型与运行时类型,在上面代码中var item1:Base,Base为item1的 编译时类型,而其运行时类型为Base。
那么在什么情况下需要进行类型识别呢?
试想:在多态调用的情况下,在一个list中存储编译类型为Base类的对象,但其运行时类型可能为Sub1,Sub2,………………SubN(这些类均为Base的子类),其中部分子类实现了ProtocolA。
遍历list,当发现对象是protocol协议的实现时,需要调用protocol协议中的某个函数。(这个时候需要进行下面介绍的强制转换)
这个时候就要需要用is来作判断了

if(item2 is AProtocol){
    print("the runtime type of item2 conforms Shape protocol")
}


if(item1 is AProtocol){
    print("the runtime type of item1 conforms Shape protocol")
}

4.2多态转型
前提:由上一段代码可知,item1,item2声明类型是Base类,item1内存中是Base,item2内存指向的是类,Sub实现了

当进行多态转型时
4.2.1可选类型
首先声明一个可选类型如下:var item3:AProtocol?这里为nil
进行转型时用as?如下:item3 = item1 as? AProtocol还是为nil
as?首先判断是否为AProtocol,如果为真 转化为”item1“的类型。

//可选类型,不成功就成nil
var item3:AProtocol?

//多态转型
item3 = item1 as? AProtocol //下溯转型为协议。               item3 nil
item3 = item2 as? AProtocol //                            item3为Sub
item3?.display()

4.2强制转化
当确切的知道待转化类型时,可以用强制转换
首先声明一个类型var item4:AProtocol
并用as!如下:item4=item2 as! AProtocol 返回任然为item的类型

在进行强制转化时,如果item2不是AProtocol编译器会提示错误“Could not cast value of type ‘Base’ (0x1136b6448) to ‘AProtocol’ (0x114bc4200)
抓化完成后 item4调用sub的函数不需要用?

var item4:AProtocol
item4=item2 as! AProtocol
//强制转化会发生错误Could not cast value of type 'Base' (0x1136b6448) to 'AProtocol' (0x114bc4200).
//item4=item1 as! AProtocol
item4.display()
if(item2 is Sub){} //也是可以用的

var item5:Sub?
//不仅能转会协议 还能转回为类型。但是转化为类型在继承体系中不符合逻辑。因为用到多态时,一般时在调用同一属性 或者时函数。协议才会出现这种情况
item5 = item2 as? Sub //这里item2也不能直接复制,因为他的声明类型是base 相当于c++的指针类型检查。要进行转换
item5?.display()

五 更多的协议形式

5.1协议的继承
BProtcol:AProtocol协议支持继承,协议只能继承协议不能继承与类;其次实现子协议的的时候也鼻血实现父协议。
这里的继承更像时一次方法叠加,只是将B,A协议的方法加在一起了

//: [Previous](@previous)

import Foundation


protocol AProtocol{
    func display()
}

protocol BProtcol:AProtocol{
    func invoke()
}

protocol CProtocol{
    func excute()
}

class ClassA:BProtcol{
    func display() {
        print("display")
    }

    func invoke() {
        print("invoke")
    }
}

5.2协议的组合
协议的组合在方法中func process(item:AProtocol & CProtocol)(这里的组合协议表示一个临时类型) 表示这里的item参数需要实现A与B两个协议。
var cb = ClassB() ;process(item: cb)
ClassB实现了b,c两个协议,而b又继承于A,所以可以调用

class ClassB:BProtcol,CProtocol{
    func display() {
        print("dispaly classb")
    }

    func invoke(){
        print("invoke classb")
    }

    func excute(){
        print("excute classb")
    }
}

// 协议组合
func process(item:AProtocol & CProtocol){
    item.display();
    item.excute()
}

var cb = ClassB()
process(item: cb)

5.3可选协议
协议的某些成员可以定义为optional
在协议以及可选方法前都要加@objc(可选方法一定要加,非可选方法可加可不加)

//可选协议
@objc protocol DProtocol{
    @objc optional var discription:String{get}
    func move()
}

class ClassC:DProtocol{
    func move(){
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值