Swift 中的Getter 和 Setter

目录

前言

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. 官方文档链接
 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

低代码(Low-Code)是什么?

#上班休息区&#xff1a;分享你的程序猿专属表情包# 目录 一、低代码概念二、低代码特点三、低代码案例四、低代码厂商五、低代码应用 低代码&#xff08;Low-Code&#xff09;是一种软件开发方法&#xff0c;它通过图形化界面和少量的编码来创建软件应用程序。低代码开发旨在…

SAP_SD模块 物料科目分配/成本简介

SAP系统各模块与财务都有个方面的集成。文本主要说明销售模块中的科目分配和成本的一个对应关系。 1、首先是在物料主数据上销售视图中的物料科目分配组&#xff0c;S1主营、S2材料等字段&#xff0c;物料销售的时候会将这个物料产生的记录到对应的科目中。 首先是物料主数据中…

如何下载b站(哔哩哔哩bilibili)的学习视频教程

方法1&#xff1a; 打开粘贴视频链接下载即可哔哩哔哩(bilibili)视频解析下载 - 保存B站视频到手机、电脑哔哩哔哩高清视频解析下载工具是一个免费的B站视频在线解析提取工具,支持提取B站APP和bilibili网站上的任何视频,提取出来的视频无水印.我们可以借助此下载器方便地将视频…

Java(六)——抽象类与接口

文章目录 抽象类和接口抽象类抽象类的概念抽象类的语法抽象类的特性抽象类的意义 接口接口的概念接口的语法接口的特性接口的使用实现多个接口接口与多态接口间的继承抽象类和接口的区别 抽象类和接口 抽象类 抽象类的概念 Java使用类实例化对象来描述现实生活中的实体&…

全文最详细的生产管理完整方案!那些让人头疼的生产管理难题及解决方法!

什么是生产管理系统&#xff1f;为何生产管理系统在企业管理中如此重要&#xff1f;生产管理系统的核心模块包括哪些&#xff1f;为何企业在生产管理系统中常常遭遇项目信息碎片化、任务分配和跟踪困难等痛点&#xff1f;又该如何针对生产管理痛点进行优化&#xff1f; 本文40…

今日选题.

诱导读者点开文章的9引真经&#xff08;二&#xff09; 标题重要么&#xff1f;新媒体、博客文通常在手机上阅读。首先所有的内容不同于纸媒&#xff0c;手机只展现标题&#xff0c;而内容都是折叠。其次读者能像看内容一样看4、5条或者7、8条标题&#xff08;区别于不同的主流…

CV大作业29期-使用YOLOv10快速实现海上红外目标检测

使用YOLOv10做红外海洋目标识别 完整的视频教程将会于28号发布&#xff0c;敬请期待&#xff01; Hi&#xff0c;大家好&#xff01;这里是肆十二&#xff01; 视频教程地址&#xff1a;【2024毕设系列】Anaconda和Pycharm如何使用_哔哩哔哩 过去几年的时间中&#xff0c;YOL…

Java面试题分享-敏感词替换 java 版本

入职啦最近更新了一些后端笔试、面试题目&#xff0c;大家看看能快速实现吗&#xff1f; 关注 入职啦 微信公众号&#xff0c;每日更新有用的知识&#xff0c;Python&#xff0c;Java&#xff0c;Golang&#xff0c;Rust&#xff0c;javascript 等语言都有 不要再用replaceAll做…

P10-P11【重载,模板,泛化和特化】【分配器的实现】

三类模板&#xff08;类模板&#xff09;&#xff08;函数模板&#xff09;&#xff08;成员函数模板&#xff09; 特化 偏特化&#xff1a;模板参数个数/模板范围 定义的分配器 以上分配器的性能和内存管理有很大不足&#xff08;在分配内存时&#xff0c;会产生很大的内存开…

探索自动发邮件的奥秘:从配置到实现

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;邮件自动化的魅力 二、配置环境&#xff1a;选择适合的SMTP服务器 示…

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版6(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言方法一、使用excel配置表excel转txt文本读取txt数据按配置信息生成僵尸 方法二、使用ScriptableObject 配置关卡信息源码结束语 前言 本节主要是推荐两种实现配置关卡信息&#xff0c;并按表生成僵尸和关卡波次 方法一、使用…

URL在线编码解码

URL在线编码解码 打开网站 在线工具网-梦幻加菲猫 选择“URL编码解码” 输入需要编码/解码的内容&#xff0c;点击“编码”/“解码”按钮 编码&#xff1a; 解码&#xff1a; 复制已经编码/解码后的内容。

【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

效果图 template 下方的image图片自行寻找替换&#xff01; <template><view><camerav-if"!tempImagePath && cameraHeight ! 0":resolution"high":frame-size"large":device-position"device":flash"f…

ModuleNotFoundError: No module named ‘osgeo‘

显示无osgeo模块 pip install osgeo显示失败 方法&#xff1a; 确保你已经安装了正确的依赖项&#xff0c;例如GDAL、GEOS和PROJ等。 方法1&#xff1a;pip install gdal 失败 方法2&#xff1a;官网下载失败&#xff0c;下载地址&#xff1a;https://www.lfd.uci.edu/~gohl…

vue3学习(四)

前言 接上篇学习笔记&#xff0c;分享3个内置组件&#xff1a;动态组件、缓存组件、分发组件基本用法。大家一起通过code的示例&#xff0c;从现象理解,注意再次理解生命周期。 一、code示例 组件A&#xff1a;CompA <script setup> import {onMounted, onUnmounted} f…

【CTF-Web】XXE学习笔记(附ctfshow例题)

XXE 文章目录 XXE0x01 前置知识汇总XMLDTD &#xff08;Document Type Definition&#xff09; 0x02 XXE0x03 XXE危害0x04 攻击方式1. 通过File协议读取文件Web373(有回显)Web374(无回显) Web375Web376Web377Web378 0x01 前置知识汇总 XML 可扩展标记语言&#xff08;eXtensi…

分享 - 树形dp

树形 d p dp dp 例1 - 基础 链接&#xff1a;树上子链 练手 分析 其实一看题就很显然的树形 d p dp dp子链在这里分为两种情况&#xff0c;如图黑链和红链 思路 d p [ i ] dp[i] dp[i] 表示以 i i i 开头的红链的最大权值易得&#xff1a; d p [ i ] m a x ( d p [ i…

SelfKG论文翻译

SelfKG: Self-Supervised Entity Alignment in Knowledge Graphs SelfKG&#xff1a;知识图中的自监督实体对齐 ABSTRACT 实体对齐旨在识别不同知识图谱&#xff08;KG&#xff09;中的等效实体&#xff0c;是构建网络规模知识图谱的基本问题。在其发展过程中&#xff0c;标…

ubuntu server版 虚拟机根目录磁盘扩容

之前一直使用桌面版ubuntu,因为项目原因需要拉取的代码太大了且项目比较多选择了体量更小的Ubuntu server版,在使用中发现根目录的磁盘很快就用满了 如上,明明分配的300G但是/dev/mapper/ubuntu--vg-ubuntu--lv 只有98G都用满了 server版本与桌面版不同的是在server版安装的时…

MySQL增删查改进阶

数据库约束表的关系增删查改 目录 一.数据库约束类型 NOT NULL约束类型 UNIQUE 唯一约束 DEFAULT 默认值约束 PRIMARY KEY&#xff1a;主键约束 FOREIGN KEY :W外键约束 二&#xff0c;查询 count&#xff08;&#xff09;两种用法 sum&#xff0c;avg&#xff0c;max…