swift入门13 初始化

You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.

通过定义初始化方法来完成初始化过程。跟oc的初始化方法不同的是,swift的初始化方法不返回值。它们的主要任务是确保一个类型的实例在第一次被使用前被正确初始化。

Instances of class types can also implement a deinitializer, which performs any custom cleanup just before an instance of that class is deallocated.

类的实例也能实现析构方法—在实例被清空之前执行自定义的清理操作。

初始化方法

Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword:

初始化方法用来创建特定类型的新实例。初始化方法的最简单的形式就像一个没有参数的实例方法,写作init:

init() {
    // 在这执行初始化操作
}

再看个例子:

struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// Prints "The default temperature is 32.0° Fahrenheit"

自定义初始化

You can customize the initialization process with input parameters and optional property types, or by assigning constant properties during initialization, as described in the following sections.

你可以自定义初始化操作,通过输入参数和可选的属性类型。具体将在下面章节介绍。

初始化参数

You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters.

你可以在初始化方法定义中提供初始化参数,用来定义自定义初始化操作中的值的类型和名字。初始化参数跟函数和方法等参数具有相同的功能和语法。

The following example defines a structure called Celsius, which stores temperatures expressed in degrees Celsius. The Celsius structure implements two custom initializers called init(fromFahrenheit:) and init(fromKelvin:), which initialize a new instance of the structure with a value from a different temperature scale:

下面的例子定义了一个Celsius结构,用来保存以摄氏度为单位的气温。Celsius结构实现了两个初始化方法 init(fromFahrenheit:) 和 init(fromKelvin:),分别用不同的气温衡量标准初始化了结构的新实例:

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0

参数名称与参数标签

As with function and method parameters, initialization parameters can have both a parameter name for use within the initializer’s body and an argument label for use when calling the initializer.

跟函数与方法参数一样,初始化参数也有参数名称和参数标签。

However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic argument label for every parameter in an initializer if you don’t provide one.

但是,与函数和方法不同的是,初始化方法并没有一个在括号前的函数名。因此,初始化方法的参数的名称和类型就用于区别哪个初始化方法被调用。因此,swift为每个初始化方法等参数提供了一个默认的参数标签,如果你不提供的话。

举个例子

struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}

Both initializers can be used to create a new Color instance, by providing named values for each initializer parameter:

两个初始化方法都能创建新的Color实例,只需要为每个初始化方法参数提供确定的值就行。

let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)

Note that it is not possible to call these initializers without using argument labels. Argument labels must always be used in an initializer if they are defined, and omitting them is a compile-time error:

注意,不能不使用参数标签就调用这些初始化方法。如果被定义了,初始化标签就必须被使用。如果省略就会报编译时错误:

let veryGreen = Color(0.0, 1.0, 0.0)
// 这会报编译时错误 - 因为不能必须用参数标签

没有参数标签的初始化方法参数

If you do not want to use an argument label for an initializer parameter, write an underscore (_) instead of an explicit argument label for that parameter to override the default behavior.

如果你不想使用初始化标签,就在该参数用上下划线 (_)代替参数标签。

举个例子

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius is 37.0

默认初始化方法

Swift provides a default initializer for any structure or class that provides default values for all of its properties and does not provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.

在swift中,那些为自己的所有的属性都提供了默认值却没有初始化方法的类和结构,系统提供了默认的初始化方法。默认的初始化方法只是创建一个新的实例并把所有属性值设为默认值。

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()

Because all properties of the ShoppingListItem class have default values, and because it is a base class with no superclass, ShoppingListItem automatically gains a default initializer implementation that creates a new instance with all of its properties set to their default values. (The name property is an optional String property, and so it automatically receives a default value of nil, even though this value is not written in the code.) The example above uses the default initializer for the ShoppingListItem class to create a new instance of the class with initializer syntax, written as ShoppingListItem(), and assigns this new instance to a variable called item.

因为ShoppingListItem的所有属性都有默认值,而且它是基类,没有父类,所以ShoppingListItem自动生成了一个初始化方法—创建一个新的实例并把所有属性的值设为默认值。name属性是一个可选的string属性,所以它有一个默认值nil,虽然在代码中没有写明。上面例子中的ShoppingListItem类的默认初始化方法写作ShoppingListItem()。

结构类型的成员逐一初始化方法(Memberwise Initializers)

Structure types automatically receive a memberwise initializer if they do not define any of their own custom initializers. Unlike a default initializer, the structure receives a memberwise initializer even if it has stored properties that do not have default values.

结构类型如果没有定义任何自定义的初始化方法的话,就会自动获得一个成员逐一初始化方法。跟默认初始化方法不一样,即使该结构存在没有默认值的存储属性,也可以介绍一个成员逐一初始化方法。

The memberwise initializer is a shorthand way to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name.

成员逐一初始化方法是对结构实例的成员属性进行初始化的快速方法。新实例的属性的初始值可以通过名字传给成员逐一初始化方法。

看个例子:

struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)

值类型的初始化方法代理

Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation, avoids duplicating code across multiple initializers.

初始化方法可以调用其他初始化方法来完成部分初始化操作。这称之为初始化方法代理,这避免了在多个初始化方法间重复编码。

The rules for how initializer delegation works, and for what forms of delegation are allowed, are different for value types and class types. Value types (structures and enumerations) do not support inheritance, and so their initializer delegation process is relatively simple, because they can only delegate to another initializer that they provide themselves. Classes, however, can inherit from other classes, as described in Inheritance. This means that classes have additional responsibilities for ensuring that all stored properties they inherit are assigned a suitable value during initialization. These responsibilities are described in Class Inheritance and Initialization below.

值类型的初始化方法代理和类的初始化方法代理的规则不尽相同。值类型(结构和枚举)不支持继承,因此它们的初始化方法代理过程相对简单,因为它们只能给他们提供的初始化方法代理。而类就不一样,类可以继承。这意味着类有着额外的责任以确保它们继承的所有存储属性在初始化时都被赋予一个合适的值。这些内容将在下面的章节介绍。

For value types, you use self.init to refer to other initializers from the same value type when writing your own custom initializers. You can call self.init only from within an initializer.

对于值类型,在写你自定义的初始化方法时,使用self.init来指向相同值类型的其他的初始化方法。你只能在一个初始化方法中调用self.init。

Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise initializer, if it is a structure) for that type. This constraint prevents a situation in which additional essential setup provided in a more complex initializer is accidentally circumvented by someone using one of the automatic initializers.

注意,如果你为一个值类型定义了一个自定义的初始化方法,你就不能在获取该类型的默认初始化方法(或者成员逐一初始化方法,如果是结构的话)了。

看例子:

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

The first Rect initializer, init(), is functionally the same as the default initializer that the structure would have received if it did not have its own custom initializers. This initializer has an empty body, represented by an empty pair of curly braces {}. Calling this initializer returns a Rect instance whose origin and size properties are both initialized with the default values of Point(x: 0.0, y: 0.0) and Size(width: 0.0, height: 0.0) from their property definitions:

第一个初始化方法 init(),跟默认初始化方法在功能上是一样的,这个初始化方法只有一个空的方法体,由一对大括号括起。调用这个初始化方法会返回一个rect实例,该实例等origin和size属性都被初始化为默认值:Point(x: 0.0, y: 0.0),Size(width: 0.0, height: 0.0),从这些属性的定义中可以看出这一点。

let basicRect = Rect()
// basicRect的origin 值是 (0.0, 0.0) ,size 值是 (0.0, 0.0)

The second Rect initializer, init(origin:size:), is functionally the same as the memberwise initializer that the structure would have received if it did not have its own custom initializers. This initializer simply assigns the origin and size argument values to the appropriate stored properties:

第二个初始化方法 init(origin:size:),与成员逐一初始化方法在功能上一致。这个初始化方法只是把origin和size参数值赋给相应的存储属性:

let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
                      size: Size(width: 5.0, height: 5.0))
// originRect的 origin值是 (2.0, 2.0) , size 值是 (5.0, 5.0)

The third Rect initializer, init(center:size:), is slightly more complex. It starts by calculating an appropriate origin point based on a center point and a size value. It then calls (or delegates) to the init(origin:size:) initializer, which stores the new origin and size values in the appropriate properties:

第三个初始化方法init(center:size:),稍微复杂点。它首先根据一个中心点( center point)和一个大小(size)的值计算出一个合适的origin点,然后调用(或者说代理)init(origin:size:) 初始化方法,init(origin:size:) 初始化方法把新的origin和size值保存到对应的属性。

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

类继承与初始化

All of a class’s stored properties—including any properties the class inherits from its superclass—must be assigned an initial value during initialization.

一个类的所有存储属性—包括从父类继承的属性—在初始化过程中都必须赋一个初始值。

Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers.

swift为类提供了两种初始化方法,以确保所有的存储属性都接收到一个初始值。这些初始化方法分别是:指定初始化方法,便捷初始化方法(convenience initializers).

指定初始化方法与便捷初始化方法(convenience initializers)

Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

指定初始化方法是一个类的首要的初始化方法。一个指定初始化方法初始化该类的所有属性,并调用合适的父类初始化方法以继续完成初始化操作。

Every class must have at least one designated initializer.

每个类都至少有一个指定初始化方法。

Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.

便捷初始化方法是一个类的次要的辅助的初始化方法。你可以定义一个便捷初始化方法,该方法从相同的类中调用一个使用指定初始化方法的参数的指定初始化方法,来设置默认值。你也可以为那个类定义一个有特殊用途的便捷初始化方法,或者为特殊的输入值类型创建一个便捷初始化方法。

You do not have to provide convenience initializers if your class does not require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent.

如果你的类不需要便捷初始化方法,你可以不提供初始化方法。只有在便捷初始化方法能节省时间或使初始化操作更简洁的情况下创建便捷初始化方法。

指定初始化方法与便捷初始化方法的语法

  • 指定初始化方法

    init(parameters) {
        statements
    }
    

  • 编辑初始化方法

    便捷初始化方法前要加上convenience关键字,以空格隔开

    convenience init(parameters) {
        statements
    }
    

类的初始化方法代理

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

为了简化指定初始化方法与便捷初始化方法之间的关系,swift为初始化方法间的代理调用设置了以下三条规则

Rule 1

A designated initializer must call a designated initializer from its immediate superclass.

规则1

指定初始化方法必须从它的当前父类调用指定初始化方法。

Rule 2
A convenience initializer must call another initializer from the same class.

规则2

便捷初始化方法必须从同一个类中调用另一个初始化方法。

Rule 3

A convenience initializer must ultimately call a designated initializer.

规则3

便捷初始化方法最后必须调用一个指定初始化方法。

可以用一张图来说明:

Here, the superclass has a single designated initializer and two convenience initializers. One convenience initializer calls another convenience initializer, which in turn calls the single designated initializer. This satisfies rules 2 and 3 from above. The superclass does not itself have a further superclass, and so rule 1 does not apply.

上图的例子中,父类有一个指定初始化方法和两个便捷初始化方法。其中一个便捷初始化方法调用另一个便捷初始化方法,另外的那个便捷初始化方法调用制定初始化方法。这满足了规则2和规则3。父类本身没有父类,所以不适用规则1.

The subclass in this figure has two designated initializers and one convenience initializer. The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above.

上图的子类有两个指定初始化方法和一个编辑初始化方法。便捷初始化方法必须调用两个指定初始化方法中的一个,因为它只能从同一个类中调用另一个初始化方法。这满足规则2和规则3.两个指定初始化方法必须调用父类的那个指定初始化方法,满足规则1.

The figure below shows a more complex class hierarchy for four classes. It illustrates how the designated initializers in this hierarchy act as “funnel” points for class initialization, simplifying the interrelationships among classes in the chain:

下图显示了一个更复杂的情况,包含四个类的体系。这体现了指定初始化方法在这个体系中对于类的初始化的“漏斗”作用,简化了此链条中的类之间的关系:

初始化的两个阶段

Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.

swift中的类有两个阶段。在第一阶段,每个存储属性都在引入它的类中被赋予一个初始值。一旦每个存储属性的初始化状态结束,第二阶段就开始了,每个类在新的实例可以使用之前都有机会对它的存储属性做进一步的处理。

The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they are initialized, and prevents property values from being set to a different value by another initializer unexpectedly.

两阶段初始化过程使得初始化既安全又能保证类体系中的各个类的灵活性。两阶段初始化防止属性的值在它们被初始化之前被获取,同时防止属性被其他的初始化方法设为其他值。

Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error:

swift的编译器执行4个安全检查步骤以确保两阶段初始化过程安全无误:

Safety check 1
A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.

安全检查1

一个指定初始化方法必须确保此类引入的所有属性在它向上调用(delegates up)父类初始化方法前被初始化。

As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all of its own properties are initialized before it hands off up the chain.

正如上面提到的,一个对象的内存只有在它所有的存储属性的初始状态都是可知的情况下才被认为是完全初始化了的。为了满足这一规则,一个指定初始化方法必须保证它所有的属性在它向上调用前被初始化。

Safety check 2
A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.

安全检查2

一个指定初始化方法必须在给一个继承的属性赋值前调用父类初始化方法。如果不这么做,指定初始化方法为继承属性赋予的新值将会被父类当作其一部分重写。

Safety check 3
A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer.

安全检查3

一个便捷初始化方法必须在给任意属性赋值前调用其他的初始化方法(包括同一个类定义的属性)。如果不这么做,便捷初始化方法赋的新值会被该类的指定初始化方法重写。

Safety check 4
An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

安全检查4

初始化方法不能调用实例方法,不能读取实例属性的值,不能调用self----直到初始化的第一阶段完成。

The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.

类实例不是完全有效的直到第一阶段结束。直到第一阶段结束,类实例才被认为是有效的,属性才能被获取,方法才能被调用。

下面是初始化过程的两个阶段:

阶段1

A designated or convenience initializer is called on a class.
Memory for a new instance of that class is allocated. The memory is not yet initialized.
A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.
The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.
This continues up the class inheritance chain until the top of the chain is reached.
Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.

在一个类上调用制定初始化方法或便捷初始化方法。

为该类的新实例分配内存。但这些内存还没初始化。

该类的一个指定初始化方法确认该类的所有存储属性都有一个值。这些存储属性的内存现在被初始化。

该指定初始化方法调用父类的一个初始化方法以对它的存储属性做相同的操作。

该操作一直沿着类体系向上执行,直到到达最顶层的类。

一旦到达最顶层的类,该类就确定了它的所有存储属性都有一个值,实例的内存就被视为完全初始化了的,阶段1完成。

阶段2

Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.
Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.

从顶层的类向下返回,在此链条中的每个指定初始化方法可以对该实例做更深入的定制化操作。初始化方法现在可以获取self并且可以修改它的属性,调用它的实例方法等等。

最后,此链条中的任何便捷初始化方法都可以对该实例做更深入的定制化操作并操作self。

看个阶段1的例子:

In this example, initialization begins with a call to a convenience initializer on the subclass. This convenience initializer cannot yet modify any properties. It delegates across to a designated initializer from the same class.

在此例中,初始化过程最开始是在子类上调用一个便捷初始化方法。这个便捷初始化方法现在不能修改任何属性。它从同一个类中调用指定初始化方法。

The designated initializer makes sure that all of the subclass’s properties have a value, as per safety check 1. It then calls a designated initializer on its superclass to continue the initialization up the chain.

这个指定初始化方法确保子类的所有属性都有一个值,就像每个安全检查1那样。然后这个指定初始化方法调用它的父类的指定初始化方法,继续初始化操作。

The superclass’s designated initializer makes sure that all of the superclass properties have a value. There are no further superclasses to initialize, and so no further delegation is needed.

父类的指定初始化方法确保父类的所有属性都有一个值。该父类没有父类需要初始化,因此调用到此为止。

As soon as all properties of the superclass have an initial value, its memory is considered fully initialized, and Phase 1 is complete.

一旦父类的所有属性都有一个初始值,它的内存就被认为是完全初始化了的,到此阶段1完成了。

再看一下阶段2的例子:

The superclass’s designated initializer now has an opportunity to customize the instance further (although it does not have to).

父类的指定初始化方法现在可以对实例进行更深入的定制操作(虽然这不是必须的)。

Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it does not have to).

一旦父类的指定初始化方法结束,子类的指定初始化方法就可以执行附加的操作了(这也不是必须的).

Finally, once the subclass’s designated initializer is finished, the convenience initializer that was originally called can perform additional customization.

最后,一旦子类的指定初始化方法结束,最开始时调用的那个便捷初始化方法就可以执行附加的操作。

可失败的初始化方法

It is sometimes useful to define a class, structure, or enumeration for which initialization can fail. This failure might be triggered by invalid initialization parameter values, the absence of a required external resource, or some other condition that prevents initialization from succeeding.

有时候为一个类,结构或枚举定义一个可以失败的初始化操作是很有用的。这种失败有可能是由无效的初始化参数值触发的,也可能是缺少必须的外部资源触发的,或是其他防止初始化成功的条件触发的。

To cope with initialization conditions that can fail, define one or more failable initializers as part of a class, structure, or enumeration definition. You write a failable initializer by placing a question mark after the init keyword (init?).

为了处理那些可以失败的初始化操作的情况,就要定义一个或多个可失败的初始化方法。可失败的初始化方法只需在init后加上问号即可(init?).

举个例子:

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

let someCreature = Animal(species: "Giraffe")
// someCreature 的类型是 Animal?, 而不是 Animal
 
if let giraffe = someCreature {
    print("An animal was initialized with a species of \(giraffe.species)")
}
// Prints "An animal was initialized with a species of Giraffe"

let anonymousCreature = Animal(species: "")
// anonymousCreature 的类型是Animal?, 而不是 Animal
 
if anonymousCreature == nil {
    print("The anonymous creature could not be initialized")
}
// Prints "The anonymous creature could not be initialized"

If you pass an empty string value to the failable initializer’s species parameter, the initializer triggers an initialization failure

如果你传了一个空字符串给可失败的初始化方法的species参数,该初始化方法会出发一个初始化失败(initialization failure)。

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

If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value.

如果一个存储属性的默认值需要某些特殊的设置,你可以使用闭包或全局函数来给这些属性提供默认值。只要该属性所属的类型的实例被初始化,该闭包或函数就被调用,闭包或函数的返回值将被赋做该属性的默认值。

class SomeClass {
    let someProperty: SomeType = {
        // 在闭包内为someProperty创建一个默认值
        // someValue 必须和 SomeType 是同一种类型
        return someValue
    }()
}



struct Chessboard {
    let boardColors: [Bool] = {
        var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...8 {
            for j in 1...8 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
    }()
    func squareIsBlackAt(row: Int, column: Int) -> Bool {
        return boardColors[(row * 8) + column]
    }
}

如果你觉得文章不错,可以给我打赏点比特股(bts),以示支持。_

BTS6jUaVVkz9gN8t9sWY9NR5UbiubSz7QtVDnEtFGpujYeqQSfQ5E

推荐阅读更多精彩内容