Swift 属性

属性分类

在Swift中, 严格意义上来讲属性可以分为两大类: 实例属性和类型属性

  • 实例属性(Instance Property): 只能通过实例去访问的属性
    • 存储实例属性(Stored Instance Property): 存储在市里的内存中, 每个实例都只有一份
  • 计算实例属性(Computed Instance Property)
  • 类型属性(Type Property): 只能通过类型去访问的属性
  • 存储类型属性(Stored Type Property): 整个程序运行过程中就只有一份内存(类似全局变量)
  • 计算类型属性(Computed Type Property)
  • 类型属性可以通过static关键字定义; 如果是类也可以通过class关键字定义
  • 实例属性属于一个特定类型的实例,每创建一个实例,实例都拥有属于自己的一套属性值,实例之间的属性相互独立
  • 为类型本身定义属性,无论创建了多少个该类型的实例,这些属性全局都只有唯一一份,这种属性就是类型属性

实例属性

上面提到Swift中相关的属性可以分为两大类:存储属性和计算属性

  • 存储属性(Stored Property)

    • 类似于成员变量,系统会为其分配内存空间,存储属性存储在实例的内存中
      存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)
    • 结构体和类可以定义存储属性, 枚举不可以定义存储属性
  • 计算属性(Computed Property)

    • 计算属性其本质就是方法(函数), 系统不会为其分配内存空间, 所以计算属性不会占用- 实例对象的内存
    • 计算属性不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和设置其他属性或变量的值

存储属性

  • Swift中存储属性可以是var修饰的变量, 也可以是let修饰的常量
  • 但是在创建类或结构体的实例时, 必须为所有的存储属性设置一个合适的初始值, 否则会报错的
  • 可以在定义属性的时候, 为其设置一个初始值
  • 可以在init初始化器里为存储实行设置一个初始值
struct Person {
    // 定义的时候设置初始值
    var age: Int = 24
    var weight: Int
}
// 使用init初始化器设置初始值
var person1 = Person(weight: 75)
var person2 = Person(age: 25, weight: 80)

  • 上面两个属性是会占用实例的内存空间的
  • 可以使用MemoryLayout获取数据类型占用的内存大小
// Person结构体实际占用的内存大小
MemoryLayout<Person>.size         // 16
// 系统为Person分配的内存大小
MemoryLayout<Person>.stride       // 16
// 内存对其参数
MemoryLayout<Person>.alignment    // 8

有一种使用方式, 输出结果一致

var person = Person(weight: 75
MemoryLayout.size(ofValue: person)
MemoryLayout.stride(ofValue: person)
MemoryLayout.alignment(ofValue: person)

计算属性

  • 计算属性不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和设置其他属性或变量的值
  • 计算属性其本质就是方法(函数), 系统不会为其分配内存空间, 所以计算属性不会占用实例对象的内存
struct Square {
    var side: Int
    var girth: Int {
        set {
            side = newValue / 4
        }
        get {
            return side * 4
        }
    }
}

// 其中set也可以使用下面方式
set(newGirth) {
    side = newGirth / 4

下面我们先看一下Square所占用的内存大小, 这里方便查看都去掉了print函数

var squ = Square(side: 4)

MemoryLayout.size(ofValue: squ)        // 8
MemoryLayout.stride(ofValue: squ)      // 8
MemoryLayout.alignment(ofValue: squ)   // 8

从上面输出结果可以看出,Square只占用8个内存大小, 也就是一个Int占用的内存大小, 如果还是看不出来, 可以看一下下面这个

struct Square {
    var girth: Int {
        get {
            return 4
        }
    }
}

// 输出结果0
print(MemoryLayout<Square>.size)   // 0
  • 从上面两个输出结果可以看出, 计算属性并不占用内存空间
  • 此外, 计算属性虽然不直接存储值, 但是却需要getset方法来取值或赋值
  • 其中通过set方法修改其他相关联的属性的值; 如果该计算属性是只读的, 则不需要set方法, 传入的新值默认值newValue, 也可以自定义
  • 通过get方法获取该计算属性的值, 即使是只读的, 计算属性的值也是可能发生改变的
  • 定义计算属性只能使用var, 不能使用let

延迟存储属性

  • 使用lazy可以定义一个延迟存储属性(Lazy Stored Property), 延迟存储属性只有在第一次使用的时候才会进行初始化
  • lazy属性修饰必须是var, 不能是let
  • let修饰的常量必须在实例的初始化方法完成之前就拥有值
class Car {
    init() {
        print("Car init")
    }
    
    func run() {
        print("Car is runing")
    }
}

class Person {
    lazy var car  = Car()
    init() {
        print("Person init")
    }
    
    func goOut() {
        car.run()
    }
}

let person = Person()
print("--------")
person.goOut()

// 输出结果
// Person init
// --------
// Car init
// Car is runing

上述代码, 在初始化car的时候如果没有lazy, 则输出结果如下

/*
Car init
Person init
--------
Car is runing
*/
  • 这也就证明了延迟存储属性只有在第一次使用的时候才会被初始化
  • 此外还有一种复杂的延迟存储属性, 有点类似于OC中的懒加载

类型属性

  • 存储类型属性(Stored Type Property): 整个程序运行过程中就只有一份内存(类似全局变量)
  • 计算类型属性(Computed Type Property): 不占用系统内存
  • 类型属性可以通过static关键字定义; 如果是类也可以通过class关键字定义
  • 存储类型属性可以声明为变量或常量,计算类型属性只能被声明为变量
  • 存储类型属性必须设置初始值, 因为存数类型属性没有init初始化器去设置初始值的方式
  • 存储类型属性默认就是延迟属性(lazy), 不需要使用lazy修饰符标记, 只会在第一次使用的时候初始化, 即使是被多个线程访问, 也能保证只会被初始化一次
// 在结构体中只能使用static
struct Person {
    static var weight: Int = 30
    static let height: Int = 100
}

// 取值
let a = Person.weight
let b = Person.height

// 赋值
Person.weight = 12
// let修饰的不可被赋值
//Person.height = 10

在类中可以使用staticclass

class Animal {
    static var name: String = "name"
    class var age: Int {
        return 10
    }
}

// 取值
let a1 = Animal.name
let a2 = Animal.age

// 赋值
Animal.name = "animal"
// class定义的属性是只读的
// Animal.age = 20

static

  • 可以修饰classstructenum类型的属性或者方法
  • 被修饰的class中的属性和方法不可以在子类中被重写, 重写会报错
  • 修饰存储属性
  • 修饰计算属性
  • 修饰类型方法
struct Person {
    // 存储属性
    static var weight: Int = 30
    // 计算属性
    static var height: Int {
        get { 140 }
    }
    // 类型方法
    static func goShoping() {
        print("Person shoping")
    }
}

class

  • 只能修饰类的计算属性和方法
  • 不能修饰类的存储属性
  • 修饰的计算属性和方法可以被子类重写
class Animal {
    // 计算属性
    class var height: Int {
        get { 140 }
    }
    // 类型方法
    class func running() {
        print("Person running")
    }
}

属性观察器

Swift中可以为非lazy的并且只能是var修饰的存储属性设置属性观察器, 形式如下

struct Person {
    var age: Int {
        willSet {
            print("willSet", newValue)
        }
        didSet {
            print("didSet", oldValue, age)
        }
    }
    
    init() {
        self.age = 3
        print("Person init")
    }
}

var p = Person()
p.age = 10
print(p.age)

/* 输出结果
Person init
willSet 10
didSet 3 10
10
*/
  • 在存储属性中定义willSetdidSet观察者,来观察和响应属性值的变化, 从上述输出结果我们也可以看到
    • willSet会传递新值, 在存储值之前被调用, 其默认的参数名是newValue
    • didSet会传递旧值, 在存储新值之后立即被调用, 其默认的参数名是oldValue
  • 当每次给存储属性设置新值时,都会调用属性观察者,即使属性的新值与当前值相同
  • 在初始化器中设置属性和在定义属性是设置初始值都不会触发willSetdidSet

如有错误地方,请指出哈~
以上就是我对Swift属性的了解啦~
请查收~
希望点个小赞啦~

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swift 中,可以使用协议来限制属性的特定实现。下面是一些示例: 1. 只读属性协议 我们可以定义一个只读属性协议,让遵循该协议的类型只能实现只读属性: ``` protocol ReadOnlyProperty { var value: Int { get } } struct MyStruct: ReadOnlyProperty { let value: Int } ``` 在上面的代码中,`ReadOnlyProperty` 协议定义了一个只读属性 `value`。然后,我们定义了一个结构体 `MyStruct`,该结构体遵循 `ReadOnlyProperty` 协议,并实现了只读属性 `value`。 2. 可写属性协议 我们可以定义一个可写属性协议,让遵循该协议的类型只能实现可写属性: ``` protocol WritableProperty { var value: Int { get set } } struct MyStruct: WritableProperty { var value: Int } ``` 在上面的代码中,`WritableProperty` 协议定义了一个可读写属性 `value`。然后,我们定义了一个结构体 `MyStruct`,该结构体遵循 `WritableProperty` 协议,并实现了可写属性 `value`。 3. 只写属性协议 我们可以定义一个只写属性协议,让遵循该协议的类型只能实现只写属性: ``` protocol WriteOnlyProperty { var value: Int { set } } class MyClass: WriteOnlyProperty { var value: Int = 0 } ``` 在上面的代码中,`WriteOnlyProperty` 协议定义了一个只写属性 `value`。然后,我们定义了一个类 `MyClass`,该类遵循 `WriteOnlyProperty` 协议,并实现了只写属性 `value`。 通过以上示例,我们可以看到如何使用协议来限制属性的特定实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值