Properties (属性)

作者: 金旭峰 | 来源:发表于2017-01-18 10:10 被阅读78次

    Propertiesassociate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures.

    属性将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。

    Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties.

    存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。

    In addition, you can define property observers to monitor changes in a property’s value, which you can respond to with custom actions. Property observers can be added to stored properties you define yourself, and also to properties that a subclass inherits from its superclass.

    另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。

    Stored Properties (存储属性)

    In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be eithervariable stored properties(introduced by thevarkeyword) orconstant stored properties(introduced by theletkeyword).

    简单来说,一个存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。

    You can provide a default value for a stored property as part of its definition, as described inDefault Property Values. You can also set and modify the initial value for a stored property during initialization. This is true even for constant stored properties, as described inAssigning Constant Properties During Initialization.

    可以在定义存储属性的时候指定默认值,请参考默认构造器一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考构造过程中常量属性的修改一节。

    The example below defines a structure calledFixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created:

    下面的例子定义了一个名为FixedLengthRange的结构体,该结构体用于描述整数的范围,且这个范围值在被创建后不能被修改.

    struct FixedLengthRange {

        var firstValue:Int

        let length:Int

    }

    varrangeOfThreeItems = FixedLengthRange(firstValue:0,length:3)

    // the range represents integer values 0, 1, and 2

    rangeOfThreeItems.firstValue=6

    // the range now represents integer values 6, 7, and 8

    Instances ofFixedLengthRangehave a variable stored property calledfirstValueand a constant stored property calledlength. In the example above,lengthis initialized when the new range is created and cannot be changed thereafter, because it is a constant property.

    FixedLengthRange的实例包含一个名为firstValue的变量存储属性和一个名为length的常量存储属性。在上面的例子中,length在创建实例的时候被初始化,因为它是一个常量存储属性,所以之后无法修改它的值。

    Stored Properties of Constant Structure Instances (常量结构体的存储属性)

    If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties:

    如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使有属性被声明为变量也不行:

    let rangeOfFourItems=FixedLengthRange(firstValue:0,length:4)

    // this range represents integer values 0, 1, 2, and 3

    rangeOfFourItems.firstValue=6

    // this will report an error, even though firstValue is a variable property

    BecauserangeOfFourItemsis declared as a constant (with theletkeyword), it is not possible to change itsfirstValueproperty, even thoughfirstValueis a variable property.

    因为rangeOfFourItems被声明成了常量(用let关键字),即使firstValue是一个变量属性,也无法再修改它了。

    This behavior is due to structures beingvalue types. When an instance of a value type is marked as a constant, so are all of its properties.

    这种行为是由于结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。

    The same is not true for classes, which arereference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties.

    属于引用类型的类(class)则不一样。把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性。

    Lazy Stored Properties (延迟存储属性)

    Alazy stored propertyis a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing thelazymodifier before its declaration.

    延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy来标示一个延迟存储属性。

    NOTE

    You must always declare a lazy property as a variable (with thevarkeyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a valuebeforeinitialization completes, and therefore cannot be declared as lazy.

    必须将延迟存储属性声明成变量(使用var关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。

    Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance’s initialization is complete. Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed.

    延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道影响值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。

    The example below uses a lazy stored property to avoid unnecessary initialization of a complex class. This example defines two classes calledDataImporterandDataManager, neither of which is shown in full:

    下面的例子使用了延迟存储属性来避免复杂类中不必要的初始化。例子中定义了DataImporter和DataManager两个类,下面是部分代码:

    class DataImporter{

    /*

        DataImporter is a class to import data from an external file.//DataImporter 是一个负责将外部文件中的数据导入的类。

        The class is assumed to take a non-trivial amount of time to initialize.//这个类的初始化会消耗不少时间。

    */

    var fileName = "data.txt"

    // the DataImporter class would provide data importing functionality here

    // 这里会提供数据导入功能

    }

    class DataManager {

    lazy var importer=DataImporter()

    var data= [String]()

    // the DataManager class would provide data management functionality here

    // 这里会提供数据管理功能

    }

    let manager=DataManager()

    manager.data.append("Some data")

    manager.data.append("Some more data")

    // the DataImporter instance for the importer property has not yet been created

    // DataImporter 实例的 importer 属性还没有被创建

    TheDataManagerclass has a stored property calleddata, which is initialized with a new, empty array ofStringvalues. Although the rest of its functionality is not shown, the purpose of thisDataManagerclass is to manage and provide access to this array ofStringdata.

    DataManager类包含一个名为data的存储属性,初始值是一个空的字符串(String)数组。这里没有给出全部代码,只需知道DataManager类的目的是管理和提供对这个字符串数组的访问即可。

    Part of the functionality of theDataManagerclass is the ability to import data from a file. This functionality is provided by theDataImporterclass, which is assumed to take a non-trivial amount of time to initialize. This might be because aDataImporterinstance needs to open a file and read its contents into memory when theDataImporterinstance is initialized.

    DataManager的一个功能是从文件导入数据。该功能由DataImporter类提供,DataImporter完成初始化需要消耗不少时间:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。

    It is possible for aDataManagerinstance to manage its data without ever importing data from a file, so there is no need to create a newDataImporterinstance when theDataManageritself is created. Instead, it makes more sense to create theDataImporterinstance if and when it is first used.

    DataManager管理数据时也可能不从文件中导入数据。所以当DataManager的实例被创建时,没必要创建一个DataImporter的实例,更明智的做法是第一次用到DataImporter的时候才去创建它。

    Because it is marked with thelazymodifier, theDataImporterinstance for theimporterproperty is only created when theimporterproperty is first accessed, such as when itsfileNameproperty is queried:

    由于使用了lazy,importer属性只有在第一次被访问的时候才被创建。比如访问它的属性fileName时:

    print(manager.importer.fileName)

    // the DataImporter instance for the importer property has now been created

    // Prints "data.txt"

    NOTE

    If a property marked with thelazymodifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.

    如果一个被标记为lazy的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。

    Stored Properties and Instance Variables (存储属性和实例变量)

    If you have experience with Objective-C, you may know that it providestwoways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property.

    如果您有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。除了属性之外,还可以使用实例变量作为属性值的后端存储。

    Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement. All information about the property—including its name, type, and memory management characteristics—is defined in a single location as part of the type’s definition.

    Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。

    Computed Properties (计算属性)

    In addition to stored properties, classes, structures, and enumerations can definecomputed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

    除存储属性外,类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter,来间接获取和设置其他属性或变量的值。

    struct Point {

    var x = 0.0, y = 0.0

    }

    struct Size {

    var width = 0.0, height = 0.0

    }

    struct Rect {

      var origin = Point()

      var size = Size()

      var center: Point {

      get {

        let centerX = origin.x + (size.width / 2)

        let centerY = origin.y + (size.height / 2)

        return Point(x: centerX, y: centerY)

    }

    set(newCenter) {

      origin.x = newCenter.x - (size.width / 2)

      origin.y = newCenter.y - (size.height / 2)

          }

        }

    }

    var square = Rect(origin: Point(x: 0.0, y: 0.0),

    size: Size(width: 10.0, height: 10.0))

    let initialSquareCenter = square.center

    square.center = Point(x: 15.0, y: 15.0)

    print("square.origin is now at (\(square.origin.x), \(square.origin.y))")

    // 打印 "square.origin is now at (10.0, 10.0)”

    This example defines three structures for working with geometric shapes:

    这个例子定义了 3 个结构体来描述几何形状:

    1. Pointencapsulates the x- and y-coordinate of a point.

    Point封装了一个(x, y)的坐标

    2. Sizeencapsulates awidthand aheight.

    Size封装了一个width和一个height

    3. Rectdefines a rectangle by an origin point and a size.

    Rect表示一个有原点和尺寸的矩形

    TheRectstructure also provides a computed property calledcenter. The current center position of aRectcan always be determined from itsoriginandsize, and so you don’t need to store the center point as an explicitPointvalue. Instead,Rectdefines a custom getter and setter for a computed variable calledcenter, to enable you to work with the rectangle’scenteras if it were a real stored property.

    Rect也提供了一个名为center的计算属性。一个矩形的中心点可以从原点(origin)和大小(size)算出,所以不需要将它以显式声明的Point来保存。Rect的计算属性center提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。

    The preceding example creates a newRectvariable calledsquare. Thesquarevariable is initialized with an origin point of(0, 0), and a width and height of10. This square is represented by the blue square in the diagram below.

    上述例子中创建了一个名为square的Rect实例,初始值原点是(0, 0),宽度高度都是10。如下图中蓝色正方形所示。

    Thesquarevariable’scenterproperty is then accessed through dot syntax (square.center), which causes the getter forcenterto be called, to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a newPointto represent the center of the square. As can be seen above, the getter correctly returns a center point of(5, 5).

    square的center属性可以通过点运算符(square.center)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的Point来表示square的中心点。如代码所示,它正确返回了中心点(5, 5)。

    Thecenterproperty is then set to a new value of(15, 15), which moves the square up and to the right, to the new position shown by the orange square in the diagram below. Setting thecenterproperty calls the setter forcenter, which modifies thexandyvalues of the storedoriginproperty, and moves the square to its new position.

    center属性之后被设置了一个新的值(15, 15),表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性center的值会调用它的 setter 来修改属性origin的x和y的值,从而实现移动正方形到新的位置。

    Shorthand Setter Declaration (简化 setter 声明)

    If a computed property’s setter does not define a name for the new value to be set, a default name ofnewValueis used. Here’s an alternative version of theRectstructure, which takes advantage of this shorthand notation:

    如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称newValue。下面是使用了简化 setter 声明的Rect结构体代码:

    struct AlternativeRect {

        var origin=Point()

        var size=Size()

        var center:Point{

        get {

            let centerX=origin.x+ (size.width/2)

            let centerY=origin.y+ (size.height/2)

           return Point(x:centerX,y:centerY)

              }

        set {

            origin.x=newValue.x- (size.width/2)

            origin.y=newValue.y- (size.height/2)

              }

        }    

    }

    Read-Only Computed Properties (只读计算属性)

    A computed property with a getter but no setter is known as aread-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value.

    只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。

    NOTE

    You must declare computed properties—including read-only computed properties—as variable properties with thevarkeyword, because their value is not fixed. Theletkeyword is only used for constant properties, to indicate that their values cannot be changed once they are set as part of instance initialization.

    必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

    You can simplify the declaration of a read-only computed property by removing thegetkeyword and its braces:

    只读计算属性的声明可以去掉get关键字和花括号:

    struct Cuboid {

        var width=0.0,height=0.0,depth=0.0

        var volume:Double{

        return width*height*depth

       }

    }

    let fourByFiveByTwo=Cuboid(width:4.0,height:5.0,depth:2.0)

    print("the volume of fourByFiveByTwo is\(fourByFiveByTwo.volume)")

    // Prints "the volume of fourByFiveByTwo is 40.0"

    This example defines a new structure calledCuboid, which represents a 3D rectangular box withwidth,height, anddepthproperties. This structure also has a read-only computed property calledvolume, which calculates and returns the current volume of the cuboid. It doesn’t make sense forvolumeto be settable, because it would be ambiguous as to which values ofwidth,height, anddepthshould be used for a particularvolumevalue. Nonetheless, it is useful for aCuboidto provide a read-only computed property to enable external users to discover its current calculated volume.

    这个例子定义了一个名为Cuboid的结构体,表示三维空间的立方体,包含width、height和depth属性。结构体还有一个名为volume的只读计算属性用来返回立方体的体积。为volume提供 setter 毫无意义,因为无法确定如何修改width、height和depth三者的值来匹配新的volume。然而,Cuboid提供一个只读计算属性来让外部用户直接获取体积是很有用的。

    Property Observers (属性观察器)

    Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value.

    属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。

    You can add property observers to any stored properties you define, except for lazy stored properties. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass. You don’t need to define property observers for nonoverridden computed properties, because you can observe and respond to changes to their value in the computed property’s setter. Property overriding is described inOverriding.

    可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。 属性重写请参考重写

    You have the option to define either or both of these observers on a property:

    可以为属性添加如下的一个或全部观察器:

    1. willSet is called just before the value is stored.

    willSet在新的值被设置之前调用

    2. didSet is called immediately after the new value is stored.

    didSet在新的值被设置之后立即调用

    If you implement awillSetobserver, it’s passed the new property value as a constant parameter. You can specify a name for this parameter as part of yourwillSetimplementation. If you don’t write the parameter name and parentheses within your implementation, the parameter is made available with a default parameter name ofnewValue.

    willSet观察器会将新的属性值作为常量参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。

    Similarly, if you implement adidSetobserver, it’s passed a constant parameter containing the old property value. You can name the parameter or use the default parameter name ofoldValue. If you assign a value to a property within its owndidSetobserver, the new value that you assign replaces the one that was just set.

    同样,didSet观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。如果在didSet方法中再次对该属性赋值,那么新值会覆盖旧的值。

    NOTE

    ThewillSetanddidSetobservers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They are not called while a class is setting its own properties, before the superclass initializer has been called.For more information about initializer delegation, seeInitializer Delegation for Value TypesandInitializer Delegation for Class Types.

    父类的属性在子类的构造器中被赋值时,它在父类中的willSet和didSet观察器会被调用,随后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器不会被调用。 有关构造器代理的更多信息,请参考值类型的构造器代理类的构造器代理规则

    Here’s an example ofwillSetanddidSetin action. The example below defines a new class calledStepCounter, which tracks the total number of steps that a person takes while walking. This class might be used with input data from a pedometer or other step counter to keep track of a person’s exercise during their daily routine.

    下面是一个willSet和didSet实际运用的例子,其中定义了一个名为StepCounter的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。

    class StepCounter {

        var totalSteps:Int=0{

        willSet(newTotalSteps) {  

        print("About to set totalSteps to\(newTotalSteps)")

    }

    didSet{

    iftotalSteps>oldValue{

    print("Added\(totalSteps-oldValue)steps")

          }

          }

      }

    }

    let stepCounter=StepCounter()

    stepCounter.totalSteps=200

        // About to set totalSteps to 200

        // Added 200 steps

    stepCounter.totalSteps=360

        // About to set totalSteps to 360

        // Added 160 steps

    stepCounter.totalSteps=896

        // About to set totalSteps to 896

        // Added 536 steps

    TheStepCounterclass declares atotalStepsproperty of typeInt. This is a stored property withwillSetanddidSetobservers.

    StepCounter类定义了一个Int类型的属性totalSteps,它是一个存储属性,包含willSet和didSet观察器。

    ThewillSetanddidSetobservers fortotalStepsare called whenever the property is assigned a new value. This is true even if the new value is the same as the current value.

    当totalSteps被设置新值的时候,它的willSet和didSet观察器都会被调用,即使新值和当前值完全相同时也会被调用。

    This example’swillSetobserver uses a custom parameter name ofnewTotalStepsfor the upcoming new value. In this example, it simply prints out the value that is about to be set.

    例子中的willSet观察器将表示新值的参数自定义为newTotalSteps,这个观察器只是简单的将新的值输出。

    ThedidSetobserver is called after the value oftotalStepsis updated. It compares the new value oftotalStepsagainst the old value. If the total number of steps has increased, a message is printed to indicate how many new steps have been taken. ThedidSetobserver does not provide a custom parameter name for the old value, and the default name ofoldValueis used instead.

    didSet观察器在totalSteps的值改变后被调用,它把新值和旧值进行对比,如果总步数增加了,就输出一个消息表示增加了多少步。didSet没有为旧值提供自定义名称,所以默认值oldValue表示旧值的参数名。

    NOTE

    If you pass a property that has observers to a function as an in-out parameter, thewillSetanddidSetobservers are always called. This is because of the copy-in copy-out memory model for in-out parameters: The value is always written back to the property at the end of the function. For a detailed discussion of the behavior of in-out parameters, seeIn-Out Parameters.

    如果将属性通过 in-out 方式传入函数,willSet和didSet也会调用。这是因为 in-out 参数采用了拷入拷出模式:即在函数内部使用的是参数的 copy,函数结束后,又对参数重新赋值。关于 in-out 参数详细的介绍,请参考输入输出参数

    Global and Local Variables (全局变量和局部变量)

    The capabilities described above for computing and observing properties are also available toglobal variablesandlocal variables. Global variables are variables that are defined outside of any function, method, closure, or type context. Local variables are variables that are defined within a function, method, or closure context.

    计算属性和属性观察器所描述的功能也可以用于全局变量局部变量。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。

    The global and local variables you have encountered in previous chapters have all beenstored variables. Stored variables, like stored properties, provide storage for a value of a certain type and allow that value to be set and retrieved.

    前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它为特定类型的值提供存储空间,并允许读取和写入。

    However, you can also definecomputed variablesand define observers for stored variables, in either a global or local scope. Computed variables calculate their value, rather than storing it, and they are written in the same way as computed properties.

    另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算结果而不是存储值,声明格式也完全一样。

    NOTE

    Global constants and variables are always computed lazily, in a similar manner toLazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with thelazymodifier.

    全局的常量或变量都是延迟计算的,跟延迟存储属性相似,不同的地方在于,全局的常量或变量不需要标记lazy修饰符。

    Local constants and variables are never computed lazily.

    局部范围的常量或变量从不延迟计算。

    Type Properties (类型属性)

    Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance.

    实例属性属于一个特定类型的实例,每创建一个实例,实例都拥有属于自己的一套属性值,实例之间的属性相互独立。

    You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are calledtype properties.

    也可以为类型本身定义属性,无论创建了多少个该类型的实例,这些属性都只有唯一一份。这种属性就是类型属性

    Type properties are useful for defining values that are universal toallinstances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C).

    类型属性用于定义某个类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。

    Stored type properties can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties.

    存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算型属性一样只能定义成变量属性。

    NOTE

    Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.

    跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。

    Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with thelazymodifier.

    存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用lazy修饰符。

    Type Property Syntax (类型属性语法)

    In C and Objective-C, you define static constants and variables associated with a type asglobalstatic variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports.

    在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(global)静态变量定义的。但是在 Swift 中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。

    You define type properties with thestatickeyword. For computed type properties for class types, you can use theclasskeyword instead to allow subclasses to override the superclass’s implementation. The example below shows the syntax for stored and computed type properties:

    使用关键字static来定义类型属性。在为类定义计算型类型属性时,可以改用关键字class来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法:

    struct SomeStructure { 

        static var storedTypeProperty="Some value."

        static var computedTypeProperty:Int{

        return1

        }

    }

    enum SomeEnumeration {

     static var storedTypeProperty="Some value."

       static var computedTypeProperty:Int{  

     return6

      }

    }

    class SomeClass {

     static var storedTypeProperty="Some value." static var computedTypeProperty:Int{

      return27

        }

    class var overrideableComputedTypeProperty:Int{

    return107

      }

    }

    NOTE

    The computed type property examples above are for read-only computed type properties, but you can also define read-write computed type properties with the same syntax as for computed instance properties.

    例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟计算型实例属性的语法相同。

    Querying and Setting Type Properties (获取和设置类型属性的值)

    Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on thetype, not on an instance of that type. For example:

    跟实例属性一样,类型属性也是通过点运算符来访问。但是,类型属性是通过类型本身来访问,而不是通过实例。比如:

    print(SomeStructure.storedTypeProperty)

        // Prints "Some value."

    SomeStructure.storedTypeProperty="Another value."

    print(SomeStructure.storedTypeProperty)

        // Prints "Another value."

    print(SomeEnumeration.computedTypeProperty)

        // Prints "6"

    print(SomeClass.computedTypeProperty)

        // Prints "27"

    The examples that follow use two stored type properties as part of a structure that models an audio level meter for a number of audio channels. Each channel has an integer audio level between0and10inclusive.

    下面的例子定义了一个结构体,使用两个存储型类型属性来表示两个声道的音量,每个声道具有0到10之间的整数音量。

    The figure below illustrates how two of these audio channels can be combined to model a stereo audio level meter. When a channel’s audio level is0, none of the lights for that channel are lit. When the audio level is10, all of the lights for that channel are lit. In this figure, the left channel has a current level of9, and the right channel has a current level of7:

    下图展示了如何把两个声道结合来模拟立体声的音量。当声道的音量是0,没有一个灯会亮;当声道的音量是10,所有灯点亮。本图中,左声道的音量是9,右声道的音量是7:

    The audio channels described above are represented by instances of theAudioChannelstructure:

    上面所描述的声道模型使用AudioChannel结构体的实例来表示:

    struct AudioChannel {

        static let thresholdLevel = 10

        static var maxInputLevelForAllChannels = 0

        var currentLevel: Int = 0 {

            didSet {

              if currentLevel > AudioChannel.thresholdLevel {

                  // 将当前音量限制在阀值之内

                  currentLevel = AudioChannel.thresholdLevel

              }

          if currentLevel > AudioChannel.maxInputLevelForAllChannels {

                // 存储当前音量作为新的最大输入音量

            AudioChannel.maxInputLevelForAllChannels = currentLevel

          }

       }

      }

    }

    TheAudioChannelstructure defines two stored type properties to support its functionality. The first,thresholdLevel, defines the maximum threshold value an audio level can take. This is a constant value of10for allAudioChannelinstances. If an audio signal comes in with a higher value than10, it will be capped to this threshold value (as described below).

    结构AudioChannel定义了 2 个存储型类型属性来实现上述功能。第一个是thresholdLevel,表示音量的最大上限阈值,它是一个值为10的常量,对所有实例都可见,如果音量高于10,则取最大上限值10(见后面描述)。

    The second type property is a variable stored property calledmaxInputLevelForAllChannels. This keeps track of the maximum input value that has been received byanyAudioChannelinstance. It starts with an initial value of0.

    第二个类型属性是变量存储型属性maxInputLevelForAllChannels,它用来表示所有AudioChannel实例的最大音量,初始值是0。

    TheAudioChannelstructure also defines a stored instance property calledcurrentLevel, which represents the channel’s current audio level on a scale of0to10.

    AudioChannel也定义了一个名为currentLevel的存储型实例属性,表示当前声道现在的音量,取值为0到10。

    ThecurrentLevelproperty has adidSetproperty observer to check the value ofcurrentLevelwhenever it is set. This observer performs two checks:

    属性currentLevel包含didSet属性观察器来检查每次设置后的属性值,它做如下两个检查:

    1. If the new value ofcurrentLevelis greater than the allowedthresholdLevel, the property observer capscurrentLeveltothresholdLevel.

    如果currentLevel的新值大于允许的阈值thresholdLevel,属性观察器将currentLevel的值限定为阈值thresholdLevel。

    2. If the new value ofcurrentLevel(after any capping) is higher than any value previously received byanyAudioChannelinstance, the property observer stores the newcurrentLevelvalue in themaxInputLevelForAllChannelstype property.

    如果修正后的currentLevel值大于静态类型属性maxInputLevelForAllChannels的值,属性观察器就将新值保存在maxInputLevelForAllChannels中。

    NOTE

    In the first of these two checks, thedidSetobserver setscurrentLevelto a different value. This does not, however, cause the observer to be called again.

    在第一个检查过程中,didSet属性观察器将currentLevel设置成了不同的值,但这不会造成属性观察器被再次调用。

    You can use theAudioChannelstructure to create two new audio channels calledleftChannelandrightChannel, to represent the audio levels of a stereo sound system:

    可以使用结构体AudioChannel创建两个声道leftChannel和rightChannel,用以表示立体声系统的音量:

    var leftChannel=AudioChannel()

    var rightChannel=AudioChannel()

    If you set thecurrentLevelof theleftchannel to7, you can see that themaxInputLevelForAllChannelstype property is updated to equal7:

    如果将左声道的currentLevel设置成7,类型属性maxInputLevelForAllChannels也会更新成7:

    leftChannel.currentLevel=7

        print(leftChannel.currentLevel)

        // Prints "7" 

     print(AudioChannel.maxInputLevelForAllChannels)

     // Prints "7"

    If you try to set thecurrentLevelof therightchannel to11, you can see that the right channel’scurrentLevelproperty is capped to the maximum value of10, and themaxInputLevelForAllChannelstype property is updated to equal10:

    如果试图将右声道的currentLevel设置成11,它会被修正到最大值10,同时maxInputLevelForAllChannels的值也会更新到10:

    rightChannel.currentLevel=11

        print(rightChannel.currentLevel)

    // Prints "10"

         print(AudioChannel.maxInputLevelForAllChannels)

    // Prints "10"

    相关文章

      网友评论

        本文标题:Properties (属性)

        本文链接:https://www.haomeiwen.com/subject/smvvbttx.html