zoukankan      html  css  js  c++  java
  • 学习Swift--属性

    属性

    • 属性将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。
    • 存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。
    • 另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。

    存储属性

    存储属性顾名思义就是存储在类和结构体中的常量或变量,当定义存储属性的时候可以给存储属性设定初始值,也可以在构造过程中设置值或改变值,

    // 声明一个结构体
    struct CustomRange {
        // 以下的代码定义了两个属性,一个为变量 一个为常量 并且都没有设置初始值
        var firstValue: Int
        let length: Int
    }
    
    // 可以调用逐一构造方法给定初始值
    var range = CustomRange(firstValue: 5, length: 6)
    
    // 因为firstValue是变量 可以在初始化之后修改值
    range.firstValue = 6
    

    注意:由于结构体是值类型,如果实例化一个常量结构体的话,不可以修改结构体中的变量属性,否则会报错

    let otherRange = CustomRange(firstValue: 3, length: 5)
    otherRange.firstValue = 5   // 此行代码会报错 因为otherRange被声明为常量,即使firstValue属性是变量也不可以修改
    

    延迟存储属性

    延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。声明延迟存储属性用<lazy>关键字,并且必须设置为变量(var)

    // 例如有一个文件下载器 初始化这个下载器会消耗大量的时间和资源
    class DataDownloader {
        var fileName: String?
        
        func start() {
            fileName = "swift.data"
        }
    }
    
    // 例如有一个文件管理者
    class DataManager {
        // 因为之前假设下载器的初始化会消耗大量时间和资源 所以使用lazy
        lazy var downloader = DataDownloader()
        var search = [String]()
    }
    
    // 初始化了文件管理者 这时downloader还没有被调用 所以Downloader不会有值
    var manager = DataManager()
    
    manager.search.append("some data")
    
    // 此时到了下面这行代码 downloader才会被初始化
    manager.downloader.start()
    

    计算属性

    除存储属性外,类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个 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()
        
        // 定义center属性 center属性不做任何存储 只是在get 和 set方法中对origin的值进行计算后修改
        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
            }
            // 下面的set方法和上面的等效 就是为新的值取了个名字
    //        set (newCenter) {
    //            origin.x = newCenter.x - size.width / 2
    //            origin.y = newCenter.y - size.height / 2
    //        }
        }
    }
    

    只读计算属性

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

    class Rectangle {
        var length = 1.0, width = 2.0, height = 5.0
    //    var volume: Double {
    //        get {
    //            return length * width * height
    //        }
    //    }
        // 一般只有getter方法时可以像下面代码这么写,当然上面的也可以
        var volume: Double {
            return length * width * height
        }
    }
    
    let rectangle: Rectangle = Rectangle()
    print("volume is (rectangle.volume)")
    // 打印出: volume is 10.0
    

    属性观察器

    属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。一般不需要为非重载的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。

    class Person {
        var name: String = "ASK" {
            willSet {
                print("the new name is (newValue)")
            }
            didSet{
                if name == "" {
                    name = oldValue
                }
                print("did set the old name is (oldValue) and the current name is (name)")
            }
        }
    }
    
    let person = Person()
    
    person.name = "Alex"
    // 打印: the new name is Alex
    // did set the old name is ASK and the current name is Alex
    

     注意: 如果在didset方法中为属性赋值的话 那么这个值会替换掉该观察器之前的值

    如果将name属性赋为""(空串)  ↓

    person.name = ""
    // 打印: the new name is
    // did set the old name is ASK and the current name is ASK
    

    类型属性

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

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

    class SomeClass {
        static var name = "class name" {
            willSet {
                print("static property will set name value")
            }
        }
        // 写成class代表子类可以重写 枚举可结构体不可以这么写
        class var overrideProperty: Int {
            return SomeClass.name.characters.count
        }
    }
    
    print("name is (SomeClass.name) length is (SomeClass.overrideProperty)")
    SomeClass.name = "the some class"
    print("name is (SomeClass.name) length is (SomeClass.overrideProperty)")
    // 打印 1 name is class name length is 10
    //     2 static property will set name value
    //     3 name is the some class length is 14
    

     

     

  • 相关阅读:
    c++ explicit 用法摘抄
    FBX SDK 从2012.1 到 2013.3 变化
    虚幻4 虚拟漫游场景 制作过程
    3DMAX 建立场景 工作流程
    保存路径选择对话框
    MFC 简单输出EXCEL
    快速使用Log4Cpp
    C# 调用 MFC DLL
    VS建立可供外部调用的MFC类DLL,C#调用MFC调用
    面试中被问到 “你对加班的看法” 该如何回答?
  • 原文地址:https://www.cnblogs.com/Alex-sk/p/5176539.html
Copyright © 2011-2022 走看看