美文网首页
08-Swift属性(Properties)

08-Swift属性(Properties)

作者: 王梓懿_1fbc | 来源:发表于2018-10-20 21:54 被阅读4次

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

    一、存储属性

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

    struct PersonStruct {
        var name:String
        let tel:Int
    }
    var liming = PersonStruct(name: "liming", tel: 10086);
    // liming实例中包含了,name变量存储属性和tel常量存储属性
    
    • 常量结构体的存储属性,创建的一个结构体实例,赋值给常量,则无法修改该实例中的任何属性,即使结构体中定义的是变量存储属性:
    // zhangsan声明为变量,即使name是变量属性,是无法再修改
    let zhangsan = PersonStruct(name: "zhangsan", tel: 10000);
    zhangsan.name = "张三";  // 这里是报错
    

    注意:
    结构体属于值类型,但值类型的实例声明为常量时,它的所有属性也就成为常量;
    类属于引用类型,将一个引用类型的实例赋值给一个常量后,仍然可以修改实例中变量属性;

    • 延迟存储属性(懒加载),即属性第一次被调用的时候才会创建并加载到内存中。与OC不同,swift专门用lazy关键字来定义某个属性为懒加载:
    【注: 如果不熟悉懒加载的,一定要自己实际操作一次,通过打印信息了解这个懒加载过程】
    // 懒加载【单例模式: 懒汉式、饿汉式,懒加载其实是属于单例模式中的懒汉式】
    class PersonClass {
        // 定义数据源属性,这个属性是属于懒加载,即在第一次使用的时候才会被调用
        lazy var dataArray : [String] = {
            // 此是dataArray初始化闭包
            () -> [String] in
            print("dataArray加载到内存中");
            return ["zhangsan", "lisi", "wangwu"]
        }()
        
        // 说hello的函数
        func speak(name:String) {
            print("hello, \(name)!");
        }
    }
    // 实例化PersonClassz
    // 注意看打印信息,此时dataArray是没有实例化的!!!
    let person = PersonClass();
    // 打印出dataArray中的名字
    print("遍历person实例中的dataArray");
    // 当person.dataArray的时候才dataArray才会被加载,即是初始化的闭包才执行调用
    for name in person.dataArray {
        person.speak(name);
    }
    

    懒加载格式:
    lazy var 变量: 类型 = { 创建变量以及初始化相关代码 }()

    二、计算属性

    • 除了存储属性外,类、结构体、枚举可以定义计算属性,计算属性不直接存储值,而是提供一个getter和一个可选setter,来间接获取和设置其他属性或变量的值:
    // set和get是针对 计算变量(Calculated property) 不可以赋值的     
    // 普通的存储变量(storage property)才是可以赋值的
    class SpeakClass {
        // _name是存储变量(Calculated property),是可以进行赋值的
        var _name:String = "";
        // name是属于计算变量(storage property),不可以赋值的,即有别于OC的set/get方法
        var name:String {
            // 写法一,定义新值参数名newName
    //        set(newName) {
    //            print("set");
    //            _name = newName;
    //        }
            // 写法二,没有定义新值参数名,直接使用默认名称newValue
            set {
                print("set");
                // 使用默认名称newValue
                _name = newValue;
            }
            get {
                print("get");
                var str = _name;
                if str.isEmpty {  
                    // 设置默认值
                    str = "swift";
                }
                return str;
            }
        }
    }
    // 实例化操作
    let speak = SpeakClass();
    // 会调用到name的get方法
    print("1-hello, \(speak.name)");
    // 会调用到name的set方法
    speak.name = "EndEvent";
    // 会调用到name的get方法
    print("2-hello, \(speak.name)");
    输出效果:
    get
    1-hello, swift
    set
    get
    2-hello, EndEvent
    

    三、属性观察器

    属性观察器监控和相应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时一样会调用。
     除了延迟属性外,其他存储属性都可以添加属性观察器,可以通过重写属性的方式为继承属性(包括存储属性和计数属性)添加属性观察器。

    注意: 不需要为非重写计算属性添加属性观察器,因为通过它的setter直接监控和响应值的变化。

    可以为属性添加一个或全部观察器:
     - willSet在新的值被设置之前调用。willSet观察器会将新的属性值作为常量参数传入,在willSet的实现代码中可以为这个参数指定名称,如果不指定也可用,默认名称为nameValue;
     - didSet在新的值被设置之后立即调用。didSet观察器会将旧的属性作为参数传入,可以为该参数命名或使用默认参数名oldValue;

    class StepCount {
        // totalSteps是存储属性,包含有`willSet`和`didSet`观察器
        // 总步数,初始化0
        var totalSteps:Int = 0 {
            willSet {  // 在新的值被设置之前调用
                print("将要设置: \(newValue)");
            }
            didSet {  // 新的值被设置之后立即调用
                print("增加步数: \(totalSteps - oldValue)");
            }
        }
    }
    // 实例化
    let step = StepCount();
    step.totalSteps = 300;
    step.totalSteps = 1000;
    

    注意: 当totalSteps设置新值的时,它的willSet和didSet观察器都会被调用,甚至当新的值和现在的值完全一样也都会调用。

    四、全局变量和局部变量

    计算属性和属性观察器说描述的模式可以是全局变量或局部变量。全部变量在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。
     全局或局部范围都可以定义计算型变量和给储存罐型变量定义观察器。计算型变量与计算属性一样,返回一个计算的值而不是存储值,声明格式完全一个。

    全局的变量和常量都是延迟计算的,与延迟存储属性相似。不同在于,全局的变量或常量不需要标记lazy关键字(即全局变量或常量都是属性懒加载)。
    局部范围的常量或变量不会计算。

    五、类型属性

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

    跟实例的存储属性不同,必须给存储类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。
    存储类型属性是延迟初始化,只有在第一次被访问的时候才会被初始化。即时被多条线程同时访问,系统也保证只会对其进行初始化一次,并且不需要用lazy关键字。

    • 类型属性语法。在C或OC中,与某个类型关联的静态常量和静态变量,是作为全局静态变量定义的。但在swift中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此作用范围也是在类型支持的范围内。使用关键字来定义类型属性:
    struct SomeStructure {
        // 使用关键字`static`定义类型属性
        static var storedTypeProperty = "Some value."
        // 类型属性
        static var computedTypeProperty: Int {
            return 1
        }
    }
    
    • 获取和设置类型属性。与实例属性一样,类型属性的访问也是通过点语法来操作。但类型属性通过类本身来获取和设置,而不是通过类的实例:
    struct SomeStructure {
        // 使用关键字`static`定义类型属性
        static var storedTypeProperty = "Some value."
        // 类型属性
        static var computedTypeProperty: Int {
            return 1
        }
    }
    // 注意是通过类型本身来获取和设置!!!
    // 获取SomeStructure中的类型属性storedTypeProperty
    print(SomeStructure.storedTypeProperty)
    // 设置SomeStructure中的类型属性storedTypeProperty
    SomeStructure.storedTypeProperty = "Another value."
    // 获取SomeStructure中的类型属性storedTypeProperty
    print(SomeStructure.storedTypeProperty)
    // 获取SomeStructure中的类型属性computedTypeProperty
    print(SomeStructure.computedTypeProperty);
    输出结果:
    Some value.
    Another value.
    1
    

    注:xcode7.3环境

    作者:西门奄
    链接:https://www.jianshu.com/u/77035eb804c3
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    相关文章

      网友评论

          本文标题:08-Swift属性(Properties)

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