快速了解所有协议
资源 : 苹果文件
协议定义了适合特定任务或功能的方法,属性和其他要求的蓝图。 然后,该协议可以由类,结构或枚举采用,以提供这些要求的实际实现。 满足协议要求的任何类型都被称为符合该协议。
因此,简单起见,一个协议会说一个struct,class或enum,如果您想成为THAT ,请执行此操作,然后再执行此操作。 例如:如果您想成为人类,则必须饮食,睡眠和休息。
类,结构体,枚举可以通过将协议名称放在类型名称后(用冒号分隔)作为其定义的一部分来采用这些协议。 可以列出多个协议,并用逗号分隔:
如果一个类具有超类,请在其采用的任何协议之前列出超类名称,然后用逗号:
swift和Objective-C都支持多级继承。 它只能有一个单一的基类。 两者都不支持多重继承。 如上图所示,仅支持协议的多个继承,以逗号分隔。
您可能已经看到UIViewController
的实现UITableview
datasource
和delegate
协议。
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { }
虽然,最佳实践是将其分组在ViewController
的单独扩展中并实现协议。
class ViewController: UIViewController {}
extension ViewController: UITableViewDataSource, UITableViewDelegate
//implement protocol methods ands variables here..extension ViewController: UITableViewDataSource, UITableViewDelegate
//implement protocol methods ands variables here..
- 协议可以具有属性以及符合该协议的类,枚举或结构可以实现的方法。
- 协议声明仅指定所需的属性名称和类型。 它没有说明该属性是存储的还是计算的。
- 协议还指定每个属性必须是可获取的还是可获取的和可设置的。
- 属性要求始终声明为变量属性,并以
var
关键字为前缀。 - 通过在类型声明后写
{ get set }
来表示可{ get set }
和可设置的属性,通过写{ get set }
来表示可{ get set }
属性。
注意:
-
{ get set }
属性不能是常量存储的属性。 它应该是一个计算属性,并且get
和set
都应该实现。 -
{ get }
属性可以是任何类型的属性,并且在需要时也可以设置该属性是有效的。
存储和计算的属性通常与特定类型的实例相关联。 但是,属性也可以与类型本身关联。 这样的属性称为类型属性。
- 在协议中定义类型属性要求时,请始终在其前面加上
static
关键字。 即使在通过类实现类型属性要求时可以使用class
或static
关键字作为前缀,该规则也适用:
如前所述,协议规定您只需要做几件事即可成为某种东西。
例如: 如果您想成为鸟,就应该飞。 否则,您应该遵守 Flyable
协议。
考虑以下示例:
在这里,我们声明了一个名为FullyNamed
的protocol
。 它具有一个名为fullName
的string
类型的gettable
存储属性。
现在,我们正在定义一个名为Person
的结构,并且说该结构符合FullyNamed
协议。 这意味着我们应该在定义的结构内实现fullName
字符串变量。 否则会给我们带来错误。
我们还可以将fullName
属性定义为计算属性。
如前所述,协议也可以具有方法。
- 协议可以具有类型方法或实例方法。
- 方法的声明方式与普通实例和类型方法完全相同,但没有大括号或方法主体。
- 可变参数是允许的。
- 不允许使用默认值。
- 与类型属性要求一样,在协议中定义类型方法要求时,请始终在其前面加上
static
关键字。 即使类型方法要求在由类实现时以class
或static
关键字为前缀也是如此:
考虑以下示例。 我相信这些是自我解释:
注意: 在上面的类中实现。 someStaticMethod(variadicParam:)
方法定义为类方法。 在协议声明中,它被定义为静态方法。
来源:文章
变异方法是我们在结构和枚举等值类型上使用的方法。 允许这些方法修改其所属的实例以及该实例的任何属性。 一个小例子:
考虑一个简单的Rectangle
结构:
scaleBy(value:)
方法修改width和height的值。 因此,应将其标记为变异。 否则,编译器会向您抛出错误。
回到变异方法的要求:
如果您定义了协议实例方法要求,该要求旨在使采用该协议的任何类型的实例发生变异,请使用mutating
关键字将该方法标记为协议定义的一部分。
如果将协议实例方法的要求标记为
mutating
,则在为类编写该方法的实现时,无需编写mutating
关键字。mutating
关键字仅由结构和枚举使用。
考虑一个实现具有变异功能的协议的枚举和类:
lightSwitch
对象应为var
因为OnOffSwitch
是值类型。
协议可以具有特定的初始化程序,如符合标准的类型可以实现的常规方法。
您可以在符合条件的类上实现协议初始化程序要求,既可以是指定的初始化程序,也可以是便捷初始化程序。 在这两种情况下,都必须使用required
修饰符标记初始化器实现:
如果子类覆盖超类中的指定初始化程序,并且还通过协议实现了匹配的初始化程序要求,请同时使用required
和override
修饰符标记初始化程序实现:
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}
协议可以具有失败的初始化程序。 合格的初始化器要求可以由合格类型上的合格或不合格初始化器来满足。 不可失败的初始化程序或隐式展开的可失败的初始化程序可以满足不可失败的初始化程序要求。
协议是一种。 您可以在许多地方使用它,例如:
- 作为函数,方法或初始化程序中的参数类型或返回类型
- 作为常量,变量或属性的类型
- 作为数组,字典或其他容器中项目的类型
- 因为协议是类型,所以其名称以大写字母开头,以匹配Swift中其他类型的名称(例如
Int
,String
和Double
)。
委托是一种设计模式,使类或结构可以将其某些职责移交给(或委托 )其他类型的实例。 委托模式也可以用作回调类型的机制。
以下代码对于具有中等知识水平的敏捷开发人员是不言自明的。 如有任何疑问,请在下面评论。
即使您无权访问现有类型的源代码,也可以扩展现有类型以采用并遵循新协议。 扩展可以向现有类型添加新的属性,方法和下标,因此可以添加协议可能要求的任何要求。
如果类型已经符合协议的所有要求,但尚未声明采用该协议,则可以使它采用带有空扩展名的协议:
类型不能仅通过满足协议的要求就自动采用协议。 他们必须始终明确声明其对协议的采用。
考虑类动物。 它具有可选的Int?
计算属性,称为age
。 这使该类符合协议Growable
。 因此,为了在所需类型应符合协议的任何地方使用该类,请使用符合Growable
协议的Animal
类的简单空扩展。
协议可用作存储在数组或字典等集合类型中的类型。
由于Animal
和Human
符合Growable
协议,因此可以将它们存储在Growable
类型的数组中。
一个协议可以继承一个或多个其他协议。 协议继承的语法类似于类继承。
假设有一个符合Inheriting
协议的结构,它也应该符合并满足Inheriting
protocol继承的所有其他协议。
通过将AnyObject
或class
协议添加到协议的继承列表中,可以将协议采用限制为类类型(而不是结构或枚举)。
在上面的示例中, SomeClassOnlyProtocol
仅可用于类类型。 编写试图采用SomeClassOnlyProtocol
的结构或枚举定义是编译时错误。
如果非类类型尝试遵循此协议,则编译器将显示如下错误:
错误:非类类型“ XXXXXXXX”不符合类协议“ YYYYYY”。
有时,一种类型需要符合多种协议。 映像接受参数的函数,该参数应符合多种协议。
您可以将多个协议组合成具有协议组成的单个需求。 协议组合的行为类似于您定义的临时本地协议,该协议具有组合中所有协议的组合要求。 协议组成未定义任何新协议类型。
在快速3和4中 ,协议组成具有SomeProtocol & AnotherProtocol
的形式。 您可以根据需要列出任意数量的协议,并用&分隔。 除了协议列表之外,在协议书第4版中,协议组成还可以包含一个类类型,该类类型可让您指定所需的超类。 迅速3无法做到这一点。
注意 :协议构成的Swift 3语法是相同的。 但是它不允许我们使用&符号将Class名称和协议一起添加。 当我尝试在组合列表中添加Animal类时,操场上抛出错误。
您可以使用is
和as
运算符,如 键入强制类型转换以检查协议一致性,并强制类型转换为特定协议。 检查和转换为协议遵循与检查和转换为类型完全相同的语法:
- 如果实例符合协议,则
is
运算符返回true
否则返回false
。 -
as?
向下运算符的版本返回协议类型的可选值,如果实例不符合该协议,则该值为nil
。 -
as!
向下转换操作符的版本会强制向下转换为协议类型,如果向下转换失败,则会触发运行时错误。
协议可以具有可选的方法和属性。这些要求不必通过符合协议的类型来实现。
可选要求以optional
修饰符作为协议定义的一部分。 提供了可选要求,以便您可以编写与Objective-C互操作的代码。 协议和可选要求都必须使用@objc
属性标记。 注意, @objc
协议只能被从Objective-C类或其他@objc
类继承的类采用。 它们不能被结构或枚举采用。
首先,我们在协议关键字前面添加
@objc
关键字。 然后,在可选方法/变量前面添加@objc optional
关键字。
在可选要求中使用方法或属性时,其类型将自动变为可选。
可以扩展协议以为符合类型的方法和方法提供实现。 这使您可以定义协议本身的行为,而不是每种类型的单独一致性或全局函数。
使用协议扩展提供默认实现
协议扩展可用于在协议本身内提供默认实现,如上一节所述。
重要说明 :如果符合类型提供了自己的必需方法或属性的实现,则将使用该实现而不是扩展提供的实现。
这是用于解释协议扩展的相同示例。 但是在这里, Fan
类通过自己定义了rotates
属性。 因此,协议扩展内部的定义将被忽略。 默认实现返回false
而Fan
类内部的定义返回true
。 看看右边的输出。
定义协议扩展时,可以指定在扩展的方法和属性可用之前必须符合的类型的约束。 您可以使用泛型的where
子句在要扩展的协议名称后编写这些约束。
在上面的示例中,它说,仅当Array
集合的元素本身是Equatable
时,才可以实现Equatable
协议。
而已 。 现在您知道什么是协议以及在哪里使用它们。
请享用!!
如果您喜欢阅读这篇文章,请分享并推荐它,以便其他人可以找到💚💚💚💚💚💚!!!!
您可以在Medium上关注我以获取新文章。 在LinkedIn上与我联系。
如果您有任何评论,问题或建议,请随时在下面的评论部分中发布它们!