-
十一、第十一部分:Protocols
Introducing protocols
关键字Protocols后面是协议的名称,后面是带有协议成员的花括号。您将注意到的最大区别是协议不包含任何实现。但是,协议没有定义可以直接实例化的类型。相反,它们为实际的具体类型定义了一个接口或模板,例如结构、类或枚举。使用协议,您可以定义一组公共行为,然后定义实现它们的实际类型
protocol Vehicle {
func accelerate()
func stop()
}
-
Protocol syntax(协议的语法)
一个协议可以被一个类、结构体或enum所采用,当另一个类型采用一个协议时,它就需要实现协议中定义的方法和属性。一旦一个类型实现了一个协议的所有成员,那么类型就被认为是符合协议的。您可以使用分号和您想要遵循的协议的名称来跟踪命名类型的名称。
-
Methods in protocols
enum Direction {
case left
case right
}
protocol DirectionalVehicle {
func accelerate()
func stop()
func turn(direction: Direction)
func description() -> String
}
值得注意的是,参数不能有默认参数, methods defined in protocols can’t contain default parameters:// 会报错
protocol OptionalDirectionVehicle {
// Build error!
func turn(direction: Direction = .left)
}
-
Properties in protocols
protocol VehicleProperties {
var weight: Int { get }
var name: String { get set }
}
当在协议中定义属性时,您必须显式地将它们的get和set写出来,这与您声明计算属性的方式有点类似。但是,就像方法一样,您不包含任何属性的实现。你开始看到这里的模式了吗?:]
事实表明必须在属性上标记get和set的,协议不知道属性的实现,这意味着它对属性的存储不作任何假设。然后您可以将这些属性作为计算属性或常规变量来实现。所有的协议都要求属性是可读的,如果它只有get需求,或者是可读和可写的,如果它有get和set需求。
即使该属性只有get需求,仍然可以将其作为存储属性或读写计算属性实现,因为协议中的需求仅是最低要求。您的一致性类型必须至少具备协议所要求的功能。
-
Initializers in protocols(协议内初始化)
虽然协议本身不能被初始化,但是它们可以声明符合类型的初始化器应该有什么:
protocol Account {
var value: Double { get set }
init(initialAmount: Double)
init?(transferAccount: Account)
}
class BitcoinAccount: Account { var value: Double = 0.0
required init(initialAmount: Double) {
value = initialAmount
}
required init?(transferAccount: Account) {
guard transferAccount.value > 0.0 else {
return nil
}
value = transferAccount.value
}
}
var accountType: Account.Type = BitcoinAccount.self
let account = accountType.init(initialAmount: 30.00)
let transferAccount = accountType.init(transferAccount: account)!
-
Protocol inheritance(继承协议)
交通工具 示例
// 交通工具
protocol Vehicle {
func accelerate() // 加速
func stop() // 停止
}
// 有轮子的交通工具
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get } // 轮子
var wheelSize: Double { get set } // 轮子尺寸
}
-
Implementing protocols(实现协议方法)
protocol Vehicle {
func accelerate()
func stop()
}
class Bike: Vehicle {
var peddling = false
var brakesApplied = false
func accelerate() {
peddling = true
brakesApplied = false
}
func stop() {
peddling = false
brakesApplied = true
}
}
-
Implementing properties(实现协议属性)
class Bike: WheeledVehicle {
let numberOfWheels = 2
var wheelSize = 16.0
var peddling = false
var brakesApplied = false
func accelerate() {
peddling = true
brakesApplied = false
}
func stop() {
peddling = false
brakesApplied = true
}
}
- ####实现get需求的选择是:
- 常存储的属性
- 可变存储属性
- 一个只读的计算属性
- 读写计算属性
- ####您实现get和set属性的选择仅限于一个变量存储的属性或一个读写计算的属性。
-
Associated types in protocols(在协议中相关类型)
您还可以添加一个关联类型作为协议成员。当在协议中使用关联类型时,您只是简单地声明该协议中使用了一种类型——而不指定应该是什么类型。这取决于协议采纳者来决定确切的类型应该是什么。
protocol WeightCalculatable {
associatedtype WeightType // 不明确的类型
func calculateWeight() -> WeightType
}
class HeavyThing: WeightCalculatable {
// This heavy thing only needs integer accuracy
typealias WeightType = Int
func calculateWeight() -> Int {
return 100
}
}
class LightThing: WeightCalculatable {
// This light thing needs decimal places
typealias WeightType = Double
func calculateWeight() -> Double {
return 0.0025
}
}
-
Implementing multiple protocols(实现多个协议)
protocol Wheeled {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
class Bike: Vehicle, Wheeled {
// Implement both Vehicle and Wheeled
}
-
Extensions and protocol conformance
这个参考extension AnchorViewController : UICollectionViewDataSource { }
protocol Reflective {
var typeName: String { get }
}
extension String: Reflective {
var typeName: String {
return "I'm a String"
}
}
let title = "Swift Apprentice!"
title.typeName // I'm a String
-
十二、第十二部分:Generics
Generics(泛型)
事实上,你已经知道了泛型。每次使用Swift数组时,都在使用泛型。这甚至可能会给人一种印象,即泛型是关于集合的,但是这种印象既不正确,又具有误导性。
在本章中,您将了解泛型的基本原理。这将为您理解如何编写自己的通用代码打下坚实的基础。最后,您将返回到Swift标准库中的泛型类型:数组、字典和optionals,使用这个新透视图。
-
Anatomy of generic types泛型类型的解剖学
class Cat {} // 猫
class Dog {}// 狗
class KeeperForCats {} // 猫的主人
class KeeperForDogs {} // 狗的主人
你要声明,每一个可能的宠物类型都意味着对应的饲养员类型的存在,你所描述的对应关系:
泛型提供了一种机制,用于使用一组类型来定义一组新的类型。
在您的示例中,您可以为管理员定义一个通用类型:
class Keeper {}
这个定义立即定义了所有对应的守护人的类型,如:
-
Generic function parameters(泛型设计)
泛型类型参数列表是在类型名称或函数名之后出现的。然后您可以在其余的定义中使用通用参数。这个函数接受两个参数并交换它们的顺序:
func swapped(_ x: T, _ y: U) -> (U, T) {
return (y, x)
}
swapped(33, "Jay") // returns ("Jay", 33)
利用泛型打印类型
func mgprint(s: K) {
print(s)
}
mgprint(s: 213)
mgprint(s: "MG明明")
Advanced Topics(高级的主题)
-
十三、第十三部分:Access Control and Code Organization
Introducing access control
通过private和fileprivate,您可以保护代码不被其他类型和文件访问。
- 在Swift3.0中
- public表示当前类、属性或者方法只能在当前module内被继承或者override,在当前module意外只能被访问;
- open表示当前类、属性或者方法可以在任何地方被继承或者override;
- final是一个辅助修饰词,表示当前类、属性或者方法在任何地方都只能被访问,不能被继承或者override;
- internal表示默认级别
- 总结
- Swfit3.0中,访问控制权限由高到低依次为:open、public、internal(默认)、fileprivate,private。
-
十四、第十四部分:Custom Operators and Subscripts
Custom Operators(自定义操作符)
-
Exponentiation operator(求幂运算符)
infix operator ** // 平方
func **(lhs: Int, rhs: Int) -> Int {
var result = lhs
for _ in 2...rhs {
result *= lhs
}
return result
}
let base = 3
let exponent = 2
let result = base ** exponent
let result1 = 4 ** 3
-
Compound assignment operator(复合赋值运算符)
infix operator **=
func **=(lhs: inout Int, rhs: Int) {
lhs = lhs ** rhs
}
var number = 3
number **= 2 // 9
var number1 = 6
number1 **= 2 // 36
// 以下代码报错,类型不一致
let baseString = "abc"
let times = 5
var multipliedString = baseString ** times
以上如果用泛型设计Generic operators
func **(lhs: T, rhs: Int) -> T {
var result = lhs
for _ in 2...rhs {
result *= lhs
}
return result
}
func **=(lhs: inout T, rhs: Int) {
lhs = lhs ** rhs
}
-
Subscripts(下标)
“数组”和“字典”中使用了子脚本,以检索数组和字典的元素。可以将它们看作是重载操作符,以便为访问集合、类、结构或枚举的元素提供快捷方式。
子脚本的原型看起来就像一个函数的签名——它有一个参数列表和一个返回类型,但是没有使用func关键字和函数的名字,而是使用子script关键字。子脚本可能有可变参数,但不能使用inout或默认参数,也不能抛出错误
-
十五、第十五部分:Error Handling
Throwing errors(抛异常)
class Pastry {
let flavor: String
var numberOnHand: Int
init(flavor: String, numberOnHand: Int) {
self.flavor = flavor
self.numberOnHand = numberOnHand
}
}
enum BakeryError: Error {
case tooFew(numberOnHand: Int)
case doNotSell
case wrongFlavor
}
class Bakery {
var itemsForSale = [
"Cookie": Pastry(flavor: "ChocolateChip", numberOnHand: 20),
"PopTart": Pastry(flavor: "WildBerry", numberOnHand: 13),
"Donut" : Pastry(flavor: "Sprinkles", numberOnHand: 24),
"HandPie": Pastry(flavor: "Cherry", numberOnHand: 6)
]
func orderPastry(item: String,
amountRequested: Int,
flavor: String) throws -> Int {
guard let pastry = itemsForSale[item] else {
throw BakeryError.doNotSell
}
guard flavor == pastry.flavor else {
throw BakeryError.wrongFlavor
}
guard amountRequested < pastry.numberOnHand else {
throw BakeryError.tooFew(numberOnHand: pastry.numberOnHand)
}
pastry.numberOnHand -= amountRequested
return pastry.numberOnHand
}
}
let bakery = Bakery()
bakery.orderPastry(item: "Albatross",
amountRequested: 1,
flavor: "AlbatrossFlavor")
-
Handling errors(处理异常)
接上代码处理
do {
try bakery.orderPastry(item: "Albatross",
amountRequested: 1, flavor: "AlbatrossFlavor")
} catch BakeryError.doNotSell {
print("Sorry, but we don't sell albatross")
} catch BakeryError.wrongFlavor {
print("Sorry, but we don't carry albatross flavor")
} catch BakeryError.tooFew {
print("Sorry, we don't have enough albatross to fulfill your order")
}
轻轻点击,关注我
轻轻点击,关注我
轻轻点击,关注我微博
浏览我的GitHub
扫一扫,关注我