swift存储属性和计算属性,swift对象存储什么意思
- 综合资讯
- 2024-10-02 02:31:41
- 3

***:Swift中的存储属性用于存储实例的常量和变量值,它直接与对象的存储相关。而计算属性不直接存储值,是提供一个 getter 和可选的 setter 来间接获取和...
***:本内容主要涉及Swift中的存储属性和计算属性,以及Swift对象存储的含义。存储属性用于存储实例的常量和变量值,是类或结构体的一部分。计算属性则不直接存储值,而是提供一个getter和可选的setter来间接获取和设置其他属性的值。而Swift对象存储可能是指在Swift语言环境下,对象在内存中的存储机制、存储布局等相关概念,但确切含义还需依据具体语境深入探究。
本文目录导读:
《深入理解Swift中的对象存储:存储属性与计算属性》
在Swift编程语言中,对象存储是一个重要的概念,它与类、结构体和枚举等类型密切相关,存储属性和计算属性是对象存储中两种关键的属性类型,它们在数据的存储、访问和操作方面发挥着截然不同但又相互补充的作用,深入理解这两种属性的特性、用法以及它们之间的区别,对于编写高效、可读且易于维护的Swift代码至关重要。
Swift中的存储属性
(一)存储属性的基本概念
1、定义
- 存储属性是与特定类或结构体的实例相关联的常量或变量,当创建一个类或结构体的实例时,存储属性会被分配相应的存储空间来存储其值,在一个表示“学生”的结构体中,可能有存储属性“姓名”和“年龄”:
```swift
struct Student {
var name: String
var age: Int
}
```
- 这里的name
和age
就是存储属性,它们分别用于存储学生的姓名(类型为String
)和年龄(类型为Int
)。
2、存储属性的初始化
- 存储属性在初始化时必须有一个初始值,对于常量存储属性(用let
定义),其初始值一旦确定就不能再改变,对于变量存储属性(用var
定义),可以在实例的生命周期内修改其值。
- 在结构体的初始化方法中,可以直接对存储属性进行初始化。
```swift
struct Point {
var x = 0.0
var y = 0.0
}
let origin = Point()
```
- 在这个例子中,Point
结构体有两个变量存储属性x
和y
,它们的初始值都被设置为0.0
,当创建origin
这个Point
结构体的实例时,x
和y
就被初始化为0.0
。
- 在类中,存储属性的初始化稍微复杂一些,如果类有继承关系,初始化过程需要遵循特定的初始化规则,以确保所有存储属性都被正确初始化。
```swift
class Vehicle {
var wheels: Int
init() {
wheels = 4
}
}
```
- 这里Vehicle
类有一个变量存储属性wheels
,在类的初始化方法init()
中,wheels
被初始化为4
。
(二)存储属性的访问级别
1、访问控制的重要性
- 访问级别决定了哪些代码可以访问存储属性,Swift提供了多种访问级别,包括private
(私有)、fileprivate
(文件私有)、internal
(内部)、public
(公开)和open
(开放)。
- 适当的访问控制有助于封装数据,防止外部代码意外地修改或访问不应该被访问的存储属性,在一个银行账户类中,账户余额应该是私有存储属性,只有类内部的方法(如存款、取款方法)才能访问和修改它。
2、不同访问级别的示例
private
访问级别表示存储属性只能在定义它的类或结构体内部访问。
```swift
class BankAccount {
private var balance = 0.0
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) {
if amount <= balance {
balance -= amount
}
}
}
```
- 在这个BankAccount
类中,balance
是私有存储属性,外部代码无法直接访问balance
,只能通过deposit
和withdraw
方法来间接操作账户余额。
internal
访问级别是默认的访问级别,如果没有显式指定访问级别,存储属性就是内部访问级别,这意味着在同一个模块内的代码可以访问该存储属性。
```swift
struct Book {
var title: String
var author: String
}
```
- 这里的title
和author
存储属性是内部访问级别,同一个模块中的其他代码可以创建Book
结构体的实例并访问title
和author
属性。
(三)存储属性在内存中的存储
1、类和结构体存储属性的内存布局差异
- 在Swift中,结构体是值类型,类是引用类型,这导致它们的存储属性在内存中的存储方式有所不同。
- 对于结构体,当创建一个结构体实例时,其存储属性的值直接存储在该实例的内存空间中,一个包含Int
和String
类型存储属性的结构体,在内存中会按照这些类型的大小顺序分配相应的空间来存储属性值。
- 而对于类,存储属性存储在类实例所指向的堆内存中,当创建一个类的实例时,实际上是在堆上分配了一块内存空间来存储类的存储属性,并且实例变量(实例的引用)存储在栈上,它指向堆中的内存块。
2、内存管理与存储属性
- 在类中,由于存储属性存储在堆内存中,需要考虑内存管理问题,Swift使用自动引用计数(ARC)来管理类实例的内存,当一个类实例的引用计数变为0时,其占用的堆内存会被释放,同时其存储属性所占用的内存也会被回收。
- 如果有一个类Person
,其中有存储属性name
和age
,当没有任何变量或常量引用Person
类的实例时,ARC会自动释放该实例以及其存储属性所占用的内存。
Swift中的计算属性
(一)计算属性的基本概念
1、定义
- 计算属性不直接存储值,而是提供一个 getter(用于获取属性值)和可选的 setter(用于设置属性值)方法来间接操作其他属性或执行计算,计算属性可以基于其他存储属性或其他计算属性的值进行计算,在一个表示矩形的结构体中,可以有计算属性area
来计算矩形的面积:
```swift
struct Rectangle {
var width: Double
var height: Double
var area: Double {
get {
return width * height
}
}
}
```
- 在这个Rectangle
结构体中,area
是一个计算属性,它没有自己的存储空间来存储值,而是通过width
和height
存储属性的值计算得到面积。
2、计算属性的简化语法
- 如果计算属性的 setter 和 getter 方法都很简单,Swift提供了简化的语法,对于上面的Rectangle
结构体,可以将area
计算属性写成:
```swift
var area: Double {width * height}
```
- 这种简化语法在 getter 方法只是简单地返回一个表达式结果时非常方便。
(二)计算属性的只读和读写
1、只读计算属性
- 只读计算属性只有 getter 方法,没有 setter 方法,这意味着外部代码只能获取该属性的值,不能修改它,在很多情况下,只读计算属性用于提供基于其他属性的计算结果,并且这个结果不应该被外部修改,在一个表示圆的结构体中,计算属性circumference
(周长)可以是只读的:
```swift
struct Circle {
var radius: Double
var circumference: Double {
get {
return 2 * Double.pi * radius
}
}
}
```
- 外部代码只能获取圆的周长,但不能通过修改circumference
来改变圆的半径或其他相关属性。
2、读写计算属性
- 读写计算属性既有 getter 方法又有 setter 方法,这使得外部代码不仅可以获取属性的值,还可以修改它,不过,在 setter 方法中,需要注意对相关属性的更新逻辑,在一个表示温度转换的类中,可以有一个读写计算属性:
```swift
class Temperature {
var celsius: Double
var fahrenheit: Double {
get {
return (celsius * 1.8)+ 32
}
set {
celsius=(newValue - 32)/1.8
}
}
init(celsius: Double) {
self.celsius = celsius
}
}
```
- 在这个Temperature
类中,fahrenheit
是一个读写计算属性,外部代码可以获取华氏温度(通过fahrenheit
的 getter),也可以设置华氏温度(通过fahrenheit
的 setter),并且在设置华氏温度时,会自动更新摄氏温度celsius
的值。
(三)计算属性的应用场景
1、数据转换与格式化
- 计算属性在数据转换和格式化方面非常有用,在一个表示日期的结构体中,可以有计算属性将日期转换为不同的格式,假设结构体Date
有存储属性year
、month
和day
,可以有计算属性将日期转换为字符串格式:
```swift
struct Date {
var year: Int
var month: Int
var day: Int
var dateString: String {
get {
return "\(year)-\(month)-\(day)"
}
}
}
```
- 这样,通过dateString
计算属性,可以方便地获取日期的字符串表示形式,而不需要在每次需要使用时都手动进行格式化操作。
2、基于其他属性的逻辑计算
- 计算属性可以用于执行基于其他属性的复杂逻辑计算,在一个表示员工工资的类中,有存储属性basicSalary
(基本工资)、bonus
(奖金)和deduction
(扣除项),可以有计算属性netSalary
(净工资)来计算员工实际到手的工资:
```swift
class EmployeeSalary {
var basicSalary: Double
var bonus: Double
var deduction: Double
var netSalary: Double {
get {
return basicSalary + bonus - deduction
}
}
init(basicSalary: Double, bonus: Double, deduction: Double) {
self.basicSalary = basicSalary
self.bonus = bonus
self.deduction = deduction
}
}
```
- 这里的netSalary
计算属性根据basicSalary
、bonus
和deduction
等存储属性的值计算出员工的净工资。
存储属性与计算属性的区别
(一)数据存储方式
1、存储属性
- 存储属性有自己的存储空间来存储数据,在内存中,无论是类中的存储属性(存储在堆内存中)还是结构体中的存储属性(直接存储在结构体实例的内存空间中),都实实在在地占用内存来保存属性的值,一个存储Int
类型的存储属性,在32位系统中会占用4个字节的内存空间来存储整数值。
2、计算属性
- 计算属性不直接存储数据,它只是在需要获取或设置属性值时执行相应的计算或操作,计算属性的值是动态计算得出的,不占用专门的内存空间来存储其结果(除了可能在计算过程中临时占用一些栈空间来执行计算逻辑),对于前面提到的Rectangle
结构体中的area
计算属性,它不会在内存中专门开辟一块空间来存储面积值,而是每次调用area
时根据width
和height
的值重新计算。
(二)初始化要求
1、存储属性
- 存储属性在初始化时必须有一个初始值,这个初始值可以是默认值(如在结构体中直接给存储属性赋初始值),也可以在初始化方法中进行设置(如在类的初始化方法中给存储属性赋值),如果没有给存储属性提供初始值,代码将无法编译,在下面的结构体中:
```swift
struct Product {
var name: String
var price: Double
}
```
name
和price
都需要有初始值,要么在定义时给定默认值,要么在创建Product
结构体实例时通过初始化方法提供值。
2、计算属性
- 计算属性没有初始化的概念,因为它不存储数据,其值是根据其他属性或逻辑动态计算得出的,在Rectangle
结构体中,area
计算属性不需要初始化,它的值取决于width
和height
存储属性的值。
(三)可变性与访问权限的处理
1、存储属性
- 存储属性可以是常量(用let
定义)或变量(用var
定义),常量存储属性一旦初始化就不能再修改,而变量存储属性可以在实例的生命周期内修改其值,对于存储属性的访问权限,可以通过访问控制修饰符(如private
、internal
等)来限制外部代码对存储属性的访问,在BankAccount
类中,balance
存储属性是私有变量存储属性,只有类内部的方法可以修改它。
2、计算属性
- 计算属性的可变性取决于它是否有 setter 方法,如果是只读计算属性(只有 getter 方法),则外部代码不能修改其值;如果是读写计算属性(既有 getter 又有 setter 方法),则外部代码可以修改其值,计算属性的访问权限也可以通过访问控制修饰符来设置,与存储属性类似,在Temperature
类中,fahrenheit
计算属性是读写属性,并且可以根据需要设置其访问权限。
在实际开发中的综合运用
(一)模型层的设计
1、使用存储属性表示实体的基本属性
- 在构建应用程序的模型层时,存储属性通常用于表示实体的基本属性,在一个社交网络应用中,对于User
类,存储属性可以包括username
(用户名)、password
(密码)、email
(电子邮件)等,这些属性是用户实体的基本信息,需要直接存储在内存中,并且在用户注册、登录等操作中会被访问和修改。
```swift
class User {
var username: String
var password: String
var email: String
init(username: String, password: String, email: String) {
self.username = username
self.password = password
self.email = email
}
}
```
2、利用计算属性提供额外的信息或操作
- 可以利用计算属性提供基于存储属性的额外信息或操作,在User
类中,可以有计算属性isValidEmail
来检查email
地址是否有效:
```swift
var isValidEmail: Bool {
get {
// 这里可以使用正则表达式或其他方法来检查电子邮件的有效性
return true
}
}
```
- 这样,在应用程序的其他部分,如用户注册表单验证时,可以方便地使用isValidEmail
计算属性来判断用户输入的电子邮件地址是否有效。
(二)视图层的交互
1、根据模型层的属性更新视图
- 在视图层与模型层交互时,存储属性和计算属性都起着重要的作用,在一个iOS应用中,有一个UIViewController
类用于显示用户信息,当从模型层获取到User
类的实例时,可以根据User
类的存储属性来更新视图中的文本框、标签等UI元素。
- 如果User
类有一个计算属性fullName
(假设由firstName
和lastName
存储属性组合而成),可以在视图层直接使用这个计算属性来显示用户的全名,而不需要在视图层再次进行组合计算。
2、视图层对模型层属性的修改反馈
- 当视图层的用户操作需要修改模型层的属性时,需要注意存储属性和计算属性的不同处理方式,如果视图层有一个文本框用于修改用户的username
,则直接修改User
类中的username
存储属性,但如果视图层有一个操作是根据用户输入的身高和体重计算身体质量指数(BMI),可以在模型层定义一个计算属性来进行计算,并且视图层可以获取这个计算属性的值来显示给用户。
在Swift中,存储属性和计算属性是对象存储的重要组成部分,存储属性用于直接存储对象的基本数据,它们在内存中有明确的存储空间,并且需要在初始化时确定初始值,计算属性则提供了一种基于其他属性或逻辑动态计算属性值的方式,不直接存储数据,在数据转换、逻辑计算和提供只读或读写属性方面具有很大的优势,在实际开发中,合理地运用存储属性和计算属性可以提高代码的可读性、可维护性和效率,同时有助于更好地封装数据和实现业务逻辑,无论是在模型层的设计还是视图层与模型层的交互中,深入理解这两种属性的特性和区别都是编写高质量Swift代码的关键。
本文链接:https://zhitaoyun.cn/116562.html
发表评论