Swift_Apprentice_v2.0语法下

  • 十一、第十一部分:Protocols

  • Introducing protocols

关键字Protocols后面是协议的名称,后面是带有协议成员的花括号。您将注意到的最大区别是协议不包含任何实现。但是,协议没有定义可以直接实例化的类型。相反,它们为实际的具体类型定义了一个接口或模板,例如结构、类或枚举。使用协议,您可以定义一组公共行为,然后定义实现它们的实际类型

protocol Vehicle {
        func accelerate()
        func stop() 
}
Swift_Apprentice_v2.0语法下_第1张图片
  • 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 {} // 狗的主人

你要声明,每一个可能的宠物类型都意味着对应的饲养员类型的存在,你所描述的对应关系:


Swift_Apprentice_v2.0语法下_第2张图片
对应关系

泛型提供了一种机制,用于使用一组类型来定义一组新的类型。
在您的示例中,您可以为管理员定义一个通用类型:

class Keeper {}

这个定义立即定义了所有对应的守护人的类型,如:


Swift_Apprentice_v2.0语法下_第3张图片
对应类型.png
  • 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明明")
Swift_Apprentice_v2.0语法下_第4张图片

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
Swift_Apprentice_v2.0语法下_第5张图片
  • 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
Swift_Apprentice_v2.0语法下_第6张图片

以上如果用泛型设计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或默认参数,也不能抛出错误

Swift_Apprentice_v2.0语法下_第7张图片

Swift_Apprentice_v2.0语法下_第8张图片
使用Subscripts之后,可以向数组和字典那样操作

  • 十五、第十五部分: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")
}
Swift_Apprentice_v2.0语法下_第9张图片
看.png


  • 轻轻点击,关注我

轻轻点击,关注我

轻轻点击,关注我微博

浏览我的GitHub


  • 扫一扫,关注我

扫一扫,关注我.jpg

你可能感兴趣的:(Swift_Apprentice_v2.0语法下)