您的位置:首页 > 移动开发 > Swift

swift的全局和局部变量以及类型属性

2016-11-19 15:53 246 查看
全局变量和局部变量

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

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

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

注意:

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

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

类型属性

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

也可以为类型本身定义属性,不管类型有多少个实例,这些属性都只有唯一一份。这种属性就是类型属性。

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

对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。

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

注意:

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

类型属性语法

在 C 或 Objective-C 中,静态常量和静态变量的定义是通过特定类型加上global关键字。在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。

使用关键字static来定义值类型的类型属性,关键字class来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法:

struct SomeStructure {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

    // 这里返回一个 Int 值

     }

}

enum SomeEnumeration {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

    // 这里返回一个 Int 值

     }

}

class SomeClass {

    class var computedTypeProperty: Int {

    // 这里返回一个 Int 值

     }

}

注意:

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

获取和设置类型属性的值

跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:

println(SomeClass.computedTypeProperty)

// 输出 "42"

 

println(SomeStructure.storedTypeProperty)

// 输出 "Somevalue."

SomeStructure.storedTypeProperty ="Another value."

println(SomeStructure.storedTypeProperty)

// 输出 "Anothervalue.”

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

后面的图表展示了如何联合使用两个声道来表示一个立体声的声音电平值。当声道的电平值是 0,没有一个灯会亮;当声道的电平值是 10,所有灯点亮。本图中,左声道的电平是 9,右声道的电平是 7。

上面所描述的声道模型使用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

       }

    }

    }

}

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

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

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

属性currentLevel包含didSet属性监视器来检查每次新设置后的属性值,有如下两个检查:

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

如果修正后的currentLevel值大于任何之前任意AudioChannel实例中的值,属性监视器将新值保存在静态属性maxInputLevelForAllChannels中。

注意:

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

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

var leftChannel = AudioChannel()

var rightChannel = AudioChannel()

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

leftChannel.currentLevel = 7

println(leftChannel.currentLevel)

// 输出 "7"

println(AudioChannel.maxInputLevelForAllChannels)

// 输出 "7"

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

 

rightChannel.currentLevel = 11

println(rightChannel.currentLevel)

// 输出 "10"

println(AudioChannel.maxInputLevelForAllChannels)

// 输出 "10"

import UIKit

struct FixedLengthRange {

    var firstValue: Int

    let length: Int

}

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)

        }

        //自定义new value的命名

        //        set(newCenter) {

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

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

        //        }

        set {

            //便捷方式,如果不自定义新值的名称,那么就会使用默认的newValue来定义

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

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

        }

    }

}

struct Cuboid {

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

    var volume: Double {

        return width * height * depth

    }

}

class DataImporter {

    /*

     DataImporter 是一个将外部文件中的数据导入的类。

     这个类的初始化会消耗不少时间。

     */

    var fileName = "data.txt"

    // 这是提供数据导入功能

}

class DataManager {

    lazy var importer = DataImporter()

    var data = [String]()

    // 这是提供数据管理功能

}

class StepCounter {

    var totalSteps: Int = 0 {

        //可以应用于任何的stored value,但是lazy类型的不适用

        willSet(newTotalSteps) {

            //传送的是将要设置的新值

            print("About to set total steps to \(newTotalSteps)")

        }

        

        didSet {

            //inface oldvalue is the default name for oldvalue and ignore here

            //oldValue 是默认的名字,存放的是上一次的旧的值

            if totalSteps > oldValue {

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

            }

        }

108e5

    }

    

}

struct SomeStructure {

    //类型属性 static

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        // 这里返回一个 Int 值

        return 3

    }

}

enum SomeEnumeration {

    //类型属性

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        // 这里返回一个 Int 值

        return 9

    }

}

class SomeClass {

    //类的类型属性 class

    class var computedTypeProperty: Int {

        // 这里返回一个 Int 值

        return 100

    }

}

class ViewController: UIViewController {

    

    override func viewDidLoad() {

        super.viewDidLoad()

        //计算属性可以用于类、结构体和枚举里,存储属性只能用于类和结构体。属性也可以直接用于类型本身,这种属性称为类型属性.另外,还可以定义属性监视器来监控属性值的变化,以此来触发一个自定义的操作。属性监视器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。计算属性和属性监视器所描述的模式也可以用于全局变量和局部变量,全局变量是在函数、方法、闭包或任何类型之外定义的变量,局部变量是在函数、方法或闭包内部定义的变量。

        storedProperty()

        calculateProperty()

        readOnlyProperty()

        classTypeProperty()

    }

    

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    

    func storedProperty() {

        var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)

        // 该区间表示整数0,1,2

        rangeOfThreeItems.firstValue = 6

        // 该区间现在表示整数6,7,8

        print("\(rangeOfThreeItems.length)")

    }

    

    func layzeProperty() {

        //延迟存储属性  延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用@lazy来标示一个延迟存储属性 必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。

        let manager = DataManager()

        manager.data.append("Some data")

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

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

        print(manager.importer.fileName)

        // DataImporter 实例的 importer 属性现在被创建了

        // 输出 "data.txt”

    }

    

    func calculateProperty() {

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

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

        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)”

        print("square.center is now at(\(square.center))")

        // 会调用get方法来输出新的值 square.center is now at(Point(x: 15.0, y: 15.0))

    }

    

    func readOnlyProperty() {

        //readonly property which only contain getter

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

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

        // 输出 "the volumeof fourByFiveByTwo is 40.0"

    }

    

    func observerProperty() {

        let stepcounter = StepCounter()

        stepcounter.totalSteps = 200

        stepcounter.totalSteps = 498

        stepcounter.totalSteps = 987

    }

    

    func classTypeProperty() {

        //也可以为类型本身定义属性,不管类型有多少个实例,这些属性都只有唯一一份。这种属性就是类型属性。类型属性用于定义特定类型所有实例共享的数据(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。

        

        //类型属性的访问也是通过.来操作,但是不同的是不再需要熟悉初始化一个相应的实例,而是直接通过名字就可以检索到

        //structure

        print("\(SomeStructure.storedTypeProperty)")

        print("\(SomeStructure.computedTypeProperty)")

        //enum

        print("\(SomeEnumeration.storedTypeProperty)")

        print("\(SomeEnumeration.computedTypeProperty)")

        //class

        print("\(SomeClass.computedTypeProperty)")

        

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐