Swift之旅_Language Guide3

趁着五一放假又看了几节官方文档,顺便记录一下碰到的知识点。


Initialization

这一小节主要讲解的是Swift中的初始化,非常的长,差点没勇气看下去。

  • Setting Initial Values for Stored Properties

Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.

类和结构体在被创建的同时必须将全部的存储属性设置一个合适的值。存储的属性不能以不确定的状态保留。

Assigning Constant Properties During Initialization
You can assign a value to a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes. Once a constant property is assigned a value, it can’t be further modified.

你可以给一个常量分配值在初始化过程中,只要在初始化完成时将其设置为一定值即可。一旦常量被分配了一个值,它不能被进一步修改。
之前还不知道常量可以在初始化方法中赋值,以为let修饰的变量就是不能赋值的。

class Person {
    let sex: String
    var age: Int?
    init(sex: String, age: Int) {
        self.sex = sex
        //Ps:可选类型可以不用在初始化方法中分配值。因为它默认分配了一个nil给它。
    }
}
  • Memberwise Initializers for Structure Types

这个之前貌似提到过,如果没有自定义过初始化方法,结构体默认会提供一个用来给每个结构体成员分配一个值。

struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
  • Designated Initializers and Convenience Initializers

指定构造器与便利构造器。简单的来说就是,指定构造器是必须的,一个类必须至少有一个指定构造器,而便利构造器不是必须的,是为了更快捷的初始化类或者在意图上更清晰。语法如下:
指定构造器:

init(<#parameters#>) {
    <#statements#>
}

便利构造器:

convenience init(<#parameters#>) {
    <#statements#>
}
  • Initializer Delegation for Class Types

To simplify the relationships between designated and convenience initializers, Swift applies the following three rules for delegation calls between initializers:

为了区别指定与便利构再去,Swift提供了以下三个规则:
1.一个指定构造器必须调用它的直接父类的指定构造器。
2.一个便利构造器必须调用同一个类的其他构造器。
3.一个便利构造器最终必须调用一个指定构造器。

文档上有一张图片比较清楚的表达了指定构造器与便利构造器之间的联系:(个人觉得其实这样做的原因就是为了能够保证这个类的每一个属性包括继承自父类的属性都能够保证在初始化的时候被分配一个值)
  • Initializer Inheritance and Overriding

Unlike subclasses in Objective-C, Swift subclasses do not inherit their superclass initializers by default. Swift’s approach prevents a situation in which a simple initializer from a superclass is inherited by a more specialized subclass and is used to create a new instance of the subclass that is not fully or correctly initialized.

Swift与OC不同,Swift不会默认继承父类的初始化方法。

  • Failable Initializers

可失败的构造器,可以在init后加上?表示这个构造方法可能会失败,失败时可以返回nil。

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}
let anonymousCreature = Animal(species: "")
// anonymousCreature is of type Animal?, not Animal
 
if anonymousCreature == nil {
    print("The anonymous creature could not be initialized")
}
// Prints "The anonymous creature could not be initialized"
  • Required Initializers

Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer:

required修饰符表明这个类的所有子类必须实现这个构造器。貌似以前重写类初始化方法的时候xcode总是让我写上这样一段代码

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

今天碰到就查了一下相关的资料,是这样说的,创建一个继承自遵循NSCoding协议类的时候,如果你定义了指定构造器或者重写了父类的指定构造器,那么就必须实现required init?(coder aDecoder: NSCoder)。fatalError("init(coder:) has not been implemented")最好改成super.init(coder: aDecoder),否则程序有些情况下会被fatalError函数终止掉app并打印。
所以我也试了一下,不去写指定构造器或者重写父类指定构造器的时候,不去实现require修饰的构造器是不会报错,应该是自动继承了。

class Person {
    required init() {
    }
}
class Student: Person {
}

但是required init?(coder aDecoder: NSCoder)这个构造器是用来干啥的应该在这个构造器里做些什么还没有找到讲的很好的资料,只知道它是NSCoding协议定义的,如果有大神了解求告知。

  • Setting a Default Property Value with a Closure or Function

用闭包或函数设置默认属性值

class SomeClass {
    let someProperty: SomeType = {
        // create a default value for someProperty inside this closure
        // someValue must be of the same type as SomeType
        return someValue
    }()
}

应该是用于类似UIView这样的初始化后需要设置一些属性的类、结构或者枚举。


Deinitialization

这一小节主要讲解的是Swift中的析构函数。只有类中有析构函数。你不能主动去调用析构函数,在arc中实例对象内存会自动释放,析构函数也会被自动调用。

Class definitions can have at most one deinitializer per class. The deinitializer does not take any parameters and is written without parentheses:

每个类最多有一个析构函数。并且析构函数没有参数,也没有圆括号:

deinit {
    // perform the deinitialization
}

之前碰到过因为block没用好导致析构函数没有执行,也就是实例对象没有释放成功,后来block中加上[weak self]之后能够成功执行,所以析构函数也可以用来验证对象有没有成功释放吧。


Optional Chaining

这一小节主要讲解的是Swift中的可选链。之前没听说这个概念,也不知道是不是该叫可选链= =,其实在平时开发中一直有用到。

class Person {
    var residence: Residence?
}
class Residence {
    var numberOfRooms = 1
}
let john = Person()
let roomCount = john.residence!.numberOfRooms

这里的john.residence!.numberOfRooms就用到了,因为Person中的residence是可选类型的,在这里是nil,所以这句代码会引发崩溃,安全的写法是john.residence?.numberOfRooms,这样john.residence是nil的时候会面就不会继续执行。

  • Calling Methods Through Optional Chaining

这里提到了通过可选链去调用方法,可选链调用方法没啥奇怪的,但是这里有提到,当你通过一个可选类型去调用方法的时候,方法的返回值会被包上可选,如Void会变成Void?, Int会变成Int?

class Person {
    var residence: Residence?
}
class Residence {
    var numberOfRooms = 1
    func printNumberOfRooms() {
        print("The number of rooms is \(numberOfRooms)")
    }
    func test() -> Int {
        return 100
    }
}
let john = Person()
print(john.residence?.printNumberOfRooms())
//打印 nil
john.residence = Residence()
print(john.residence?.test())
//打印 Optional(100)

Error Handling

这一小节主要讲解的是Swift中的异常。

  • Representing and Throwing Errors

通常Swift中的错误都是用一个枚举类型并且遵循Error这个空协议来表示的,定义一个错误类型和抛出错误如下:

enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

中间一串都是讲的异常的用法,个人感觉没啥难点,后面有提到另一种用法

  • Representing and Throwing Errors

可以在try后面加一个?,try?,其实这也符合Swift语法的特性,加上?之后如果throw一个error,后面表达式的值则为nil。如下面代码x与y做的事情其实一样:

func someThrowingFunction() throws -> Int {
    // ...
}
let x = try? someThrowingFunction()
 
let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}
  • Disabling Error Propagation

有?自然有!与之对应,如果你肯定这个方法不会抛出异常,可以在try后面加上!,这样就不需要去catch错误,但是如果抛出了异常则会崩溃。

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
  • Specifying Cleanup Actions

defer,这个在之前也提到过,defer代码块中的代码是在一个方法return之后再调用的,无论函数是否抛出错误,都执行该代码。不过这里有补充一个知识点,就是函数中的第一个defer最后调用,第二个倒数第二个调用,以此类推,最后的一个defer则是第一个调用:

func test() {
    defer {
        print("1")
    }
    defer {
        print("2")
    }
    defer {
        print("3")
    }
    print("函数执行完毕!")
}
test()
//函数执行完毕!
//3
//2
//1

Type Casting

这一小节主要讲解的是Swift中类型转换。
前半截主要是讲了is as的用法,感觉没啥特别的知识点,翻到最后算是找到一个以前不知道的。

  • Type Casting for Any and AnyObject

Any can represent an instance of any type at all, including function types.
AnyObject can represent an instance of any class type.

之前也一直不知道Any和AnyObject的区别,看了文档才发现原来Any是可以代表任何类型的实例,包括函数类型,而AnyObject则是表示任何类的实例对象。


Nested Types

这一小节主要讲解的是Swift中的嵌套类型,就是讲在结构体、类和枚举中定义结构体、类和枚举,没啥可讲的,就是有一个注意点,在结构体、类或枚中嵌套的结构体、类或枚举,在外部需要使用的时候需要在前面加上嵌套的类型,说着有点绕,直接看代码:

class Person: NSObject {
    enum Sex {
        case Man
        case Woman
    }  
}
let sex = Person.Sex.Man

Extensions

这一小节主要讲解的是Swift中的扩展。Extensions类似Objective-C中的categories,可以给一个类、结构体、枚举或者协议增加新的方法。
Swift中的Extensions有以下功能:
1.添加计算实例属性和计算类型属性
2.定义实例方法和类方法
3.提供新的初始化方法
4.定义下标
5.定义和使用新的嵌套类型
6.让一个已存在的类型遵循一个协议

  • Extension Syntax

Extensions使用方法:

extension SomeType {
    // new functionality to add to SomeType goes here
}

遵循协议:

extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}

推荐阅读更多精彩内容