Swift 属性

目录

一、属性

swift 中跟实例相关的属性可分为2大类

  • 存储属性(Stored Property)
    • 类似于成员变量这个概念
    • 存储在实例的内存中
    • 结构体、类可以定义存储属性
    • 枚举不可以定义存储属性

枚举值不能定义存储属性,枚举只用来存储索引(占用1个字节)和关联值

  • 计算属性(Computed Property)
    • 本质就是方法(函数)
    • 不占用实例的内存
    • 枚举、结构体、类都可以定义计算属性
struct Circle {
	// 存储属性 - 结构体和类可定义
  var radius: Double
  // 计算属性
  var diameter: Double {
    set {
      radius = newValue
    }
    /*
    set (newDiameter) {
      radius = newDiameter
    }
    */
    get {
      radius * 2
    }
  }
}

1.1 存储属性

存储属性是一个作为特定类和结构体实例一部分的常量或变量。

  • let 用来声明常量,常量的值一旦设置好便不能再被更改;
  • var 用来声明变量,变量的值可以在将来设置为不同的值。
class LGTeacher{ 
	// age\name:存储属性
	var age: Int 
	let name: String 
}

1.2 计算属性

计算属性:存储值,他们提供 gettersetter 来修改和获取值。
(对于存储属性来说可以是常量或变量,但计算属性必须定义为变量。)

struct square{ 
	// 存储属性
	var width: Double

	// 计算属性
	var area: Double{ 
		get{ 
			return width * hegith
		}
		set{
			self.width = newValue
		}
	}
}

枚举RawValue原理:

// 原始值可能不需要存储,只是一个方法
enum Season: Int {
	case spring = 1, summer, autumn, winter
}

// 枚举原始值 rawValue的本质是:只读计算属性
enum TestEnum: Int {
	case test1 = 1, test2, test3, test4
	var rawValue: Int {
		switch self {
			case test1:
				return 10
      		case test2:
				return 10
      		case test3:
				return 10
      		case test4:
				return 10
		}
	}
}

三、属性观察者

属性观察者会观察用来观察属性值的变化, willSet 当属性将被改变调用,即使这个值与 原有的值相同,而 didSet 在属性已经改变之后调用。

class SubjectName{ 
	var subjectName: String = "" { 
		willSet{ 
			print("subjectName will set value \(newValue)") 
		}
		didSet{ 
			print("subjectName has been changed \(oldValue)")
		}
	}
}

1、初始化期间设置属性时不会调用 willSet 和 didSet 观察者;只有在为完全初始化的实例分配新值时才会调用它们。
2、属性观察者只对存储属性起作用

四、延迟存储属性

使用lazy可以定义一个延迟存储属性,在第一次用到属性时才会初始化

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

class PhotoView {
	lazy var image: Image = {
    	let url =""
    	let data = Data(url: url)
    	Image(data: data)
  }()
}

lazy属性特性:

    1. lazy属性必须是var,不能是let
    1. let必须在实例的初始化方法完成之前就拥有值
    1. 如果多条线程同时访问lazy,无法保证属性只被初始1次
    1. 当结构体包含一个延迟存储属性时,只有var才能访问延迟存储属性,因为延迟属性初始化时需要改变结构体的内存
    struct Point {
    	var x: Int
    	var y: Int
    	lazy var z = 0 ❎
    }
    let p = Point()
    print(p.z) // 访问lazy属性,会重新改变结构体内存,这是不允许的
    

五、类型属性

  • 类型属性其实就是一个全局变量
  • 类型属性只会被初始化一次
- 不同于存储实例属性,必须给存储类型属性设定初始值
  - 因为类型没有像实例那样的init初始化器来初始化存储属性
- 存储类型属性默认就是lazy,会在第一次使用的时候才初始化(实际会调用dispatch_once_t初始化)
  - 就算被多个线程访问,保证只会初始化一次
  - 存储类型属性可以是let
- 枚举类型也可以定义类型属性(存储类型属性、计算类型属性):类型属性不存储在枚举的实例内部

Person & Person.self 区别:
Person.self == metadata(元类型),Person.type(元类型的类型),AnyClass(AnyObject.type)

六、属性位置

// Swift 对象的类型结构是 metadata 和 refcount 组成

class JHTest {
    func test() {}
}

// 函数调用:-> metedata -> 函数地址(metedata + 偏移量)
struct Metadata{
    var kind: Int // 代表类型(类、结构体、枚举、可选、函数等等)
    var superClass: Any.Type
    var cacheData: (Int, Int)
    var data: Int
    var classFlags: Int32
    var instanceAddressPoint: UInt32
    var instanceSize: UInt32
    var instanceAlignmentMask: UInt16
    var reserved: UInt16
    var classSize: UInt32
    var classAddressPoint: UInt32
    var typeDescriptor: UnsafeMutableRawPointer
    var iVarDestroyer: UnsafeRawPointer
}

// typeDescriptor: Class, Struct, Enum 都有自己的类描述
struct TargetClassDescriptor{
    var flags: UInt32
    var parent: UInt32
    var name: Int32
    var accessFunctionPointer: Int32
    var fieldDescriptor: Int32  // 记录了当前的属性信息
    var superClassType: Int32
    var metadataNegativeSizeInWords: UInt32
    var metadataPositiveSizeInWords: UInt32
    var numImmediateMembers: UInt32
    var numFields: UInt32
    var fieldOffsetVectorOffset: UInt32
    var Offset: UInt32
    var size: UInt32

    //V-Table(函数表)
}

// fieldDescriptor
struct FieldDescriptor { 
	MangledTypeName int32 
	Superclass int32 
	Kind uint16 
	FieldRecordSize uint16 
	NumFields uint32  // 多少个属性值
	FieldRecords [FieldRecord] // 每个属性的信息
}

struct FieldRecord{ 
	Flags uint32 
	MangledTypeName int32 
	FieldName int32 
}

属性观察器、计算属性的功能,同样可以应用在全局变量、局部变量身上

  • 0
    点赞
  • 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、付费专栏及课程。

余额充值