老司机带你快速熟悉Swift 4.1(二)

对象和类

1、关键字 class

使用class后跟班的名字来创建一个班级。类中的属性声明与常量或变量声明的写法相同,只不过它在类的上下文中。同样,方法和函数声明的写法也是一样的。

通过在类名后加括号来创建一个类的实例。使用点语法来访问实例的属性和方法。


2、init关键字(初始化器)
可以使用 init 创建一个类。即初始化器在创建实例时设置一个类。


!!!请注意:要将 self.name 属性 与初始值设定项参数区分开来。在创建类的实例时,初始值设定项的参数会像函数调用一样传递。每个属性都需要赋值 - 无论是在其声明中(如同 numberOfSides)还是在初始化程序中(与之一样 name )。

deinit如果您需要在释放对象之前执行一些清理, 请使用此命令创建一个取消初始化程序。

子类在其类名后面包含它们的超类名称,并用冒号分隔。不要求类为任何标准根类继承,所以您可以根据需要包含或省略超类。

覆盖超类实现的子类上override的方法被标记为 - 无意中覆盖方法,如果没有override,则被编译器检测为错误。编译器还检测override那些实际上并没有覆盖超类中任何方法的方法。

  1. class Square: NamedShape {
  2.    var sideLength: Double
  3.    
  4.    init(sideLength:Double, name: String) {
  5.        self.sideLength =sideLength
  6.        super.init(name:name)
  7.        numberOfSides = 4
  8.     }
  9.    
  10.    func area() -> Double {
  11.        return sideLength * sideLength
  12.     }
  13.    
  14.    override func simpleDescription() -> String {
  15.        return "A square with sides of length \(sideLength)."
  16.     }
  17. }
  18. let test = Square(sideLength:5.2, name: "my test square")
  19. test.area()
  20. test.simpleDescription()


枚举和结构

1、枚举:

使用enum创建一个枚举。像类和所有其他命名类型一样,枚举可以具有与它们关联的方法。


默认情况下,Swift分配原始值从零开始,每次递增1,但您可以通过显式指定值来更改此行为。在上面的例子中,Ace明确给出了一个原始值1,其余的原始值是按顺序分配的。您也可以使用字符串或浮点数作为枚举的原始类型。使用该rawValue属性来访问枚举个案的原始值。

使用init?(rawValue:)初始化程序从原始值创建枚举的实例。它返回匹配原始值的枚举情况或者nil没有匹配的情况Rank

  1. if let convertedRank = Rank(rawValue: 3) {
  2. let threeDescription = convertedRank.simpleDescription()
  3. }


枚举的实例值是实际值,而不仅仅是编写其原始值的另一种方式。事实上,在没有有意义的原始价值的情况下,您不必提供一个。


注意hearts上面引用枚举情况的两种方式:当为hearts常量赋值时,枚举大小写Suit.hearts由全名引用,因为该常量没有指定显式类型。在交换机内部,枚举案由缩写形式引用,.hearts因为self已知该值是套装。只要该值的类型已知,您就可以使用缩写形式。


如果枚举具有原始值,则这些值将作为声明的一部分来确定,这意味着特定枚举案例的每个实例始终具有相同的原始值。枚举案例的另一种选择是将值与案例相关联 - 这些值在创建实例时确定,并且对于枚举案例的每个实例它们可以不同。您可以将关联的值视为像枚举大小写实例的存储属性一样工作。例如,考虑从服务器请求日出和日落时间的情况。服务器或者以请求的信息作出响应,或者以对出错的描述做出响应。

  1. enum ServerResponse {
  2. case result(String, String)
  3. case failure(String)
  4. }
  5. let success = ServerResponse.result("6:00 am", "8:09 pm")
  6. let failure = ServerResponse.failure("Out of cheese.")
  7. switch success {
  8. case let .result(sunrise, sunset):
  9. print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
  10. case let .failure(message):
  11. print("Failure... \(message)")
  12. }


2、结构:

使用struct创建的结构。结构支持许多与类相同的行为,包括方法和初始化器。结构和类之间最重要的差异之一就是结构在代码中传递时总是被复制,但类是通过引用传递的。


协议和扩展

1、 使用 protocol 申报的协议。
  1. protocol ExampleProtocol {
  2. var simpleDescription: String { get }
  3. mutating func adjust()
  4. }


2、类,枚举和结构都可以采用协议。


请注意在声明中使用mutating关键字SimpleStructure来标记修改结构的方法。声明SimpleClass不需要任何标记为变异的方法,因为类上的方法总是可以修改类。


3、extension的使用

extension向现有类型添加功能,例如新方法和计算属性。您可以使用扩展来将协议一致性添加到其他地方声明的类型,甚至可以添加到从库或框架导入的类型。

  1. extension Int: ExampleProtocol {
  2. var simpleDescription: String {
  3. return "The number \(self)"
  4. }
  5. mutating func adjust() {
  6. self += 42
  7. }
  8. }
  9. print(7.simpleDescription)


您可以像使用任何其他命名类型一样使用协议名称,例如,创建具有不同类型的对象集合,但都符合单个协议。当您使用类型为协议类型的值时,协议定义之外的方法不可用。

  1. let protocolValue: ExampleProtocol = a
  2. print(protocolValue.simpleDescription)
  3. // print(protocolValue.anotherProperty) // Uncomment to see the error

即使变量protocolValue具有运行时类型SimpleClass,编译器也会将其视为给定的类型ExampleProtocol这意味着除了协议一致性之外,您不能意外地访问类实现的方法或属性。


错误处理

1、使用任何采用Error协议的类型代表错误

使用throw抛出一个错误,并throws标记,可以抛出一个错误的功能。如果在函数中抛出错误,函数会立即返回,并调用函数的代码处理错误。

有几种方法可以处理错误。一种方法是使用docatchdo内部,您可以通过try在其前写入代码来标记可能导致错误的代码catch块内,错误会自动给出名称,error除非您给它一个不同的名称。



您可以提供catch处理特定错误的多个块。你在写完一个模式后catch就像case在切换之后一样。

  1. do {
  2. let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
  3. print(printerResponse)
  4. } catch PrinterError.onFire {
  5. print("I'll just put this over here, with the rest of the fire.")
  6. } catch let printerError as PrinterError {
  7. print("Printer error: \(printerError).")
  8. } catch {
  9. print(error)
  10. }


2、

处理错误的另一种方法是使用try?将结果转换为可选项。如果函数抛出一个错误,则丢弃该特定错误并返回结果nil否则,结果是包含函数返回值的可选项。

  1. let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
  2. let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")

defer写的是在函数中的所有其它代码后执行代码块,只是在函数返回之前。无论函数是否引发错误,代码都会执行。defer即使需要在不同的时间执行它们,您也可以使用它们将设置和清理代码编写在一起。

  1. var fridgeIsOpen = false
  2. let fridgeContent = ["milk", "eggs", "leftovers"]
  3. func fridgeContains(_ food: String) -> Bool {
  4. fridgeIsOpen = true
  5. defer {
  6. fridgeIsOpen = false
  7. }
  8. let result = fridgeContent.contains(food)
  9. return result
  10. }
  11. fridgeContains("banana")
  12. print(fridgeIsOpen)


泛型

在尖括号内写一个名字来创建一个通用函数或类型。

  1. func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
  2. var result = [Item]()
  3. for _ in 0..<numberOfTimes {
  4. result.append(item)
  5. }
  6. return result
  7. }
  8. makeArray(repeating: "knock", numberOfTimes: 4)


您可以制作通用形式的函数和方法,以及类,枚举和结构。

  1. // Reimplement the Swift standard library's optional type
  2. enum OptionalValue<Wrapped> {
  3. case none
  4. case some(Wrapped)
  5. }
  6. var possibleInteger: OptionalValue<Int> = .none
  7. possibleInteger = .some(100)


where在正文前面 使用指定需求列表 - 例如,要求类型实现协议,要求两种类型相同,或要求类具有特定的超类。

  1. func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
  2. where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
  3. for lhsItem in lhs {
  4. for rhsItem in rhs {
  5. if lhsItem == rhsItem {
  6. return true
  7. }
  8. }
  9. }
  10. return false
  11. }
  12. anyCommonElements([1, 2, 3], [3])


注意:写作<T: Equatable>与写作相同<T> ... where T: Equatable


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>