Swift 中的Getter 和 Setter

news2025/1/16 17:52:50

目录

前言

1. 什么是Getter和Setter

1.定义

2.作用

2.属性

1.存储属性

2.计算属性

3.属性观察者

3. 使用 Getter 和 Setter 的场景

1.数据转换

2.懒加载

3.数据验证和限制

4.触发相关操作

4.自定义Getter 和 Setter

5. 参考资料


前言

        属性是 Swift 编程中的基本组成部分,它们在类、结构体和枚举中存储和管理数据。属性可以分为存储属性、计算属性和属性观察者,每种属性都有其特定的用途和重要性。

        在 Swift 编程中,属性是存储和管理数据的关键组件。属性可以分为存储属性和计算属性。在处理计算属性时,我们经常会使用到 getter 和 setter,这两个概念对于控制属性的读取和写入行为非常重要。

        这篇博客主要介绍下Swift中的属性和settter和getter方法

1. 什么是Getter和Setter

1.定义

        Getter和Setter是访问属性值的两种方法。它们主要用于计算属性,通过这两种方法,我们可以在读取或设置属性值时执行特定的逻辑。

  1. Getter:用来获取属性的值。
  2. Settter:用来设置属性的值。

2.作用

        GetterSetter 是访问属性值的两种方法。它们主要用于计算属性,通过这两种方法,我们可以在读取或设置属性值时执行特定的逻辑。

  1. 数据验证和清理:在 setter 中可以添加数据验证逻辑,确保属性值符合预期。在 getter 中可以进行数据格式化或其他处理。
  2. 延迟计算:在 getter 中可以进行延迟计算,只在需要时才计算属性值,从而节省资源。
  3. 触发相关行为:在 setter 中可以触发其他属性的更新或执行其他副作用,比如通知观察者属性值的变化。
  4. 封装复杂逻辑:通过 getter 和 setter,可以将复杂的计算或逻辑封装在属性中,保持代码的简洁和可读性。

2.属性

        在Swift中,属性可以分为存储属性和计算属性。存储属性是类或者结构体的一部分,用来存储常来那个或者变量的值。它们是最基本的属性类型,直接存储在对象的内存中。

1.存储属性

        存储属性的类型

        1.常量存储属性(let):定义后不能改变,只能初始化的时候设置值。

        2.变量存储属性(var):定义后值可以改变。

        我们可以通过下面的代码看一下存储属性的用法:

struct Person {
    let firstName: String // 常量存储属性
    var lastName: String  // 变量存储属性
}

var person = Person(firstName: "John", lastName: "Doe")
print("Full Name: \(person.firstName) \(person.lastName)") // 输出: Full Name: John Doe

// 修改 lastName 的值
person.lastName = "Smith"
print("Full Name: \(person.firstName) \(person.lastName)") // 输出: Full Name: John Smith

// 尝试修改 firstName 的值(会产生编译错误)
// person.firstName = "Jane"

        在这个例子中,firstName 是一个常量存储属性,一旦赋值就不能改变。而 lastName 是一个变量存储属性,可以随时修改。

       我们还可以使用lazy关键字来延迟存储属性。

class DataManager {
    var data = [String]()
    init() {
        print("DataManager初始化.")
    }
}

class ViewController {
    lazy var dataManager = DataManager() // 延迟存储属性
    init() {
        print("ViewController初始化.")
    }
}

let viewController = ViewController()
print("Accessing dataManager...")
viewController.dataManager.data.append("Sample Data")
print("DataManager data: \(viewController.dataManager.data)")

        控制台输出结果如下:

        我们可以看到,dataManager属性在首次访问的时候才被初始化,这样可以避免在ViewController初始化的时候进行不必要的开销。

        可选类型的属性允许为空,可以使用?来定义可选类型的存储属性。

struct Car {
    var model: String
    var owner: String?
}

        在下面的代码中,Car的owner属性就是可选的。

2.计算属性

        在 Swift 中,计算属性(Computed Properties)是类、结构体或枚举的一部分,它们不直接存储值,而是提供一个 getter 和可选的 setter 来间接获取和设置其他属性或值。计算属性在访问时动态计算其值。

        我们可以使用var定义计算属性,提供一个getter和setter方法。getter用于计算和返回值,setter用来设置值。

         以下面的代码为例,Rectangle的area属性是通过计算来获取的。

struct Rectangle {
    var width: Double
    var height: Double
    
    var area: Double {
        return width * height
    }
}

let rect = Rectangle(width: 10.0, height: 5.0)
print("Rectangle Area: \(rect.area)") // 输出: Rectangle Area: 50.0

        上面的代码中,area属性是通过计算来获取的。例子中的area只读的,我们也可以设置既可读也可写的。

        在下面的代码中,我们可以通过设置area获得height,也可以设置width和height获取area属性。

struct Rectangle {
    var width: Double
    var height: Double
    
    var area: Double {
        get {
            return width * height
        }
        set {
            height = newValue / width
        }
    }
}

var rect = Rectangle(width: 10.0, height: 5.0)
print("Rectangle Area: \(rect.area)") // 输出: Rectangle Area: 50.0

rect.area = 100.0
print("New Height: \(rect.height)") // 输出: New Height: 10.0

        我们还可以给枚举类型设置计算属性,下面的例子中,我们定义了两个计算属性inCelsius和inFahrenheit,用于在摄氏度和华氏度之间转换温度。

enum Temperature {
    case celsius(Double)
    case fahrenheit(Double)
    
    var inCelsius: Double {
        switch self {
        case .celsius(let value):
            return value
        case .fahrenheit(let value):
            return (value - 32) * 5 / 9
        }
    }
    
    var inFahrenheit: Double {
        switch self {
        case .celsius(let value):
            return (value * 9 / 5) + 32
        case .fahrenheit(let value):
            return value
        }
    }
}

let tempInCelsius = Temperature.celsius(25.0)
print("Temperature in Fahrenheit: \(tempInCelsius.inFahrenheit)") // 输出: Temperature in Fahrenheit: 77.0

let tempInFahrenheit = Temperature.fahrenheit(77.0)
print("Temperature in Celsius: \(tempInFahrenheit.inCelsius)") // 输出: Temperature in Celsius: 25.0

3.属性观察者

        在 Swift 中,属性观察者(Property Observers)可以监视和响应属性值的变化。无论新值是否与当前值相同,属性观察者都会在属性值改变时调用。你可以为存储属性添加观察者,但不能为计算属性添加观察者。

        观察者属性有两种类型:

  1. willSet:在属性值被存储之前的调用
  2. didSet:在新值被存储之后立即调用

        这两个观察者允许我们在属性值变化前后执行自定义的代码。willSet 会传入新的属性值作为参数,didSet 会传入旧的属性值作为参数:

        例如下面的代码中,我们有一个StepCounter类,它有一个观察者属性couter,默认值为0

class StepCounter {
    var counter: Int = 0 {
        willSet(counter) {
            print("counter willSet 设置为 \(counter)")
        }
        didSet {
            if counter > oldValue {
                print("counter didSet \(counter - oldValue) steps")
            }
        }
    }
}

        我们使用下面的代码调用它:

let stepCounter = StepCounter()        
stepCounter.counter = 200        
stepCounter.counter = 360
stepCounter.counter = 896

        控制台打印信息如下:

        属性观察者是 Swift 中强大的工具,用于监视和响应存储属性值的变化。通过 willSetdidSet,你可以在属性值变化前后执行自定义操作。这对于验证数据、更新 UI 或者实现一些依赖逻辑非常有用。

3. 使用 Getter 和 Setter 的场景

        上面介绍了属性的类型和getter和setter的用法,我们接下来看一下getter和setter的使用场景

1.数据转换

class Temperature {
    var celsius: Double = 0.0

    var fahrenheit: Double {
        get {
            return celsius * 9 / 5 + 32
        }
        set {
            celsius = (newValue - 32) * 5 / 9
        }
    }
}

var temp = Temperature()
temp.celsius = 25
print("Celsius: \(temp.celsius)") // Celsius: 25.0
print("Fahrenheit: \(temp.fahrenheit)") // Fahrenheit: 77.0

temp.fahrenheit = 98.6
print("Celsius: \(temp.celsius)") // Celsius: 37.0
print("Fahrenheit: \(temp.fahrenheit)") // Fahrenheit: 98.6

2.懒加载

        懒加载在iOS开发过程中经常使用,我们ViewController中使用的UI组件都可以使用懒加载的方式去声明。

class DataManager {
    lazy var data: [String] = {
        // 复杂的初始化逻辑
        return ["Data1", "Data2", "Data3"]
    }()
}

let manager = DataManager()
// Data will be loaded only when accessed for the first time
print(manager.data) // ["Data1", "Data2", "Data3"]

3.数据验证和限制

        例如在下面的代码中,我们可以使用set方法对输入的年龄做限制。

class Person {
    private var _age: Int = 0

    var age: Int {
        get {
            return _age
        }
        set {
            if newValue >= 0 && newValue <= 120 {
                _age = newValue
            } else {
                print("Invalid age")
            }
        }
    }
}

var person = Person()
person.age = 25
print("Age: \(person.age)") // Age: 25

person.age = -5 // Invalid age
print("Age: \(person.age)") // Age: 25

4.触发相关操作

        例如在下面的Rectangle中,我们设置好width和height之后,会自动获取area的值。

class Rectangle {
    var width: Double = 0.0
    var height: Double = 0.0

    var area: Double {
        get {
            return width * height
        }
        set {
            height = newValue / width
        }
    }
}

var rect = Rectangle()
rect.width = 10
rect.height = 5
print("Area: \(rect.area)") // Area: 50.0

rect.area = 100
print("Height: \(rect.height)") // Height: 10.0

4.自定义Getter 和 Setter

        更多的时候,我们使用到setter和setter的场景是自定义我们自己的Getter和setter方法,格式如下:

var propertyName: PropertyType {
    get {
        // 返回计算的值
    }
    set {
        // 执行自定义的设置逻辑
    }
}

5. 参考资料

1. 官方文档链接
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1790857.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu中PDF阅读器和编辑器

1. 福昕PDF编辑器 1.1. 下载地址 PDF阅读器下载_PDF编辑器下载_PDF软件官方下载_福昕软件官网 1.2. 安装 sudo dpkg -i signed_com.foxit.foxitpdfeditor_xxx_amd64_UOS.deb 2. WPS DPF 2.1. 下载地址 WPS Office 2019 for Linux-支持多版本下载_WPS官方网站 2.2. 使用 …

NSS题目练习7

[MoeCTF 2022]baby_file 打开看见一串源代码&#xff0c;需要get传参传入file 题目提示php伪协议 用dirsearch扫描发现flag.php 用php伪协议查看&#xff0c;回显一串base64编码 解码后得到flag [鹤城杯 2021]Middle magic 读取这两个文件 一个php正则表达式 补充&#xff1a…

背包问题(01背包及其优化(滚动数组和逆序枚举))

终于是完结了AC自动机&#xff0c;接下来开个新坑——背包问题&#xff0c;背包的种类还是很多的&#xff0c;之前有学过&#xff0c;但都是这里看一点&#xff0c;那里看一点&#xff0c;导致现在都搞混了&#xff0c;所以重新系统看看这方面的内容。 先从简单的入手——01背包…

如何在 Java 中使用 JOptionPane 显示消息对话框

在 Java 开发中&#xff0c;JOptionPane 是一个非常实用的类&#xff0c;可以用来显示各种类型的对话框&#xff0c;例如信息对话框、警告对话框、错误对话框等。今天&#xff0c;我们将深入探讨如何使用 JOptionPane.showMessageDialog 方法来显示消息对话框&#xff0c;以及如…

面试被问准备多久要孩子?这样回答

听说有人面试被问到多久要孩子的问题&#xff0c;当时觉得很尴尬&#xff0c;不知如何回答&#xff0c;怕回答的不好不被录用&#xff0c;其实你可以这样回答&#xff0c;让面试官心满意足。 A 面试官&#xff1a;结婚了吗&#xff1f; 我&#xff1a;结婚了 面试官&#xff1…

MySQL—函数—数值函数(基础)

一、引言 首先了解一下常见的数值函数哪些&#xff1f;并且直到它们的作用&#xff0c;并且演示这些函数的使用。 二、数值函数 常见的数值函数如下&#xff1a; 注意&#xff1a; 1、ceil(x)、floor(x) &#xff1a;向上、向下取整。 2、mod(x,y)&#xff1a;模运算&#x…

Linux学习笔记9

Linux 进程间通信 介绍一下管道&#xff0c;管道是一种特殊的文件&#xff0c;它通过文件描述符来进行访问和操作 管道的读写操作是阻塞式的&#xff0c;如果没有数据可读&#xff0c;读操作会被阻塞&#xff0c;直到有数据可读&#xff1b;如果管道已满&#xff0c;写操作也…

Transformer 论文重点

摘要 提出了一个 Transformer 模型&#xff0c;针对于一个机器翻译的小任务上表现结果比当时所有模型的效果都好&#xff0c;并且架构相比其它更加简单&#xff0c;后面就火到了发现什么方向都能用的地步。 介绍 循环神经网络&#xff0c;特别是长短时记忆[ 13 ]和门控循环[…

计算机SCI期刊,中科院3区,专业性强,审稿专业

一、期刊名称 Frontiers in Neurorobotics 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机科学 影响因子&#xff1a;3.1 中科院分区&#xff1a;3区 三、期刊征稿范围 神经机器人前沿在体现自主系统的科学和技术及其应用方面发表了严格的同行评审…

解决Mac无法上网/网络异常的方法,重置网络

解放方法 1、前往文件夹&#xff1a;/Library/Preferences/SystemConfiguration 2 、在弹窗中输入上边的地址 3 、把文件夹中除了下图未选中的文件全部删掉&#xff0c;删除时需要输入密码 4 、重启mac 电脑就搞定了。

Windows 宿主机访问 VirtualBox 虚拟机中创建的 docker 容器中的 mysql8.0 的数据

一、场景需求 在开发环境中&#xff0c;一般使用 windows 系统进行开发&#xff0c;但需要在 linux 系统中创建运行 mysql8.0 的 docker 容器中进行测试&#xff08;win10特定版本或win11才能安装 docker&#xff09;&#xff0c;为了方便还需要在 windows 系统中通过 SQLyog …

操作系统笔记(1)进程相关

进程概念&#xff1a; 进程同步&#xff1a;多个相关进程在执行次序上进行协调&#xff0c;使并发执行的进程之间能按照一定的规则共享系统资源&#xff0c;并能很好的合作&#xff0c;从而使进程的执行具有可再现性。 进程之间可能存在互斥或者同步的关系。 互斥(间接相互制…

Android gradle kts 8.0以上版本配置签名和修改APK输出名字

目录 概述修改签名配置新建签名文件目录配置签名信息使用签名信息打包 修改APK名称 概述 之前写过一篇文章是通过Kotlin的Dsl结合gradle编写的插件来管理项目依赖&#xff0c;我是从一个开源项目叫DanDanPlayAndroid项目上学到的&#xff0c;那时还没有使用toml文件来管理项目…

模糊小波神经网络(MATLAB 2018)

模糊系统是一种基于知识或规则的控制系统&#xff0c;从属于智能控制&#xff0c;通过简化系统的复杂性&#xff0c;利用控制法来描述系统变量之间的关系&#xff0c;采用语言式的模糊变量来描述系统&#xff0c;不必对被控对象建立完整的数学模型。相比较传统控制策略&#xf…

【Git】分支管理 -- 详解

一、理解分支 分支就是科幻电影里面的平行宇宙&#xff0c;当你正在电脑前努力学习 C 的时候&#xff0c;另一个你正在另一个平行宇宙里努力学习 JAVA。 如果两个平行宇宙互不干扰&#xff0c;那对现在的你也没啥影响。不过&#xff0c;在某个时间点&#xff0c;两个平行宇宙…

Jenkins流水线pipeline--基于上一章的工作流程

1流水线部署 1.流水线文本名Jenkinsfile,将流水线放入gitlab远程仓库代码里面 2构建参数 2pipeline脚本 Jenkinsfile文件内容 pipeline {agent anyenvironment {key"value"}stages {stage("拉取git仓库代码") {steps {deleteDir()checkout scmGit(branc…

小熊家务帮day5-day7 客户管理模块1 (小程序认证,手机验证码认证,账号密码认证,修改密码,找回密码等)

客户管理模块 1.认证模块1.1 认证方式介绍1.1.1 小程序认证1.1.2 手机验证码登录1.1.3 账号密码认证 1.2 小程序认证1.2.1 小程序申请1.2.2 创建客户后端工程jzo2o-customer1.2.3 开发部署前端1.2.4 小程序认证流程1.2.4.1 customer小程序认证接口设计Controller层Service层调用…

运营商卷大模型,云厂商霸主地位不保?

文&#xff5c;艺 思 编&#xff5c;王一粟 经过了2023年的小试牛刀&#xff0c;2024年&#xff0c;三大运营商带着大模型一路狂飙。 刚刚过去的5月&#xff0c;中国电信、中国移动、中国联通三大运营商集体完成了新一轮的大模型进化&#xff0c;特别是围绕大模型的研发与…

2023年计算机图形学课程知识总结

去年就该写的&#xff0c;但是去年这个时候太忙了。 就写来自己看看。留个记录留个念 文章目录 1. 图形&#xff0c;图像的定义2. 点阵、矢量3. 走样&#xff0c;反走样4. 字符裁剪精度&#xff08;1&#xff09; 串精度&#xff08;2&#xff09; 字符精度&#xff08;3&…

【ubuntu软件版本管理】利用update-alternatives管理ubuntu软件

​ 我们有的时候希望在安装了新软件之后保留旧版本的软件&#xff0c;比如希望保留旧版本的gcc&#xff0c;以防以前写的C编译出问题&#xff0c;这时候就需要版本管理软件update-alternatives。 ​ 在此之前我们需要先弄清楚&#xff0c;什么是ubuntu的软件&#xff1f;拿C源…