Swift-26-面向对象OOP编程-类和属性定义

devtools/2024/9/19 7:31:52/ 标签: swift, 开发语言, ios, objective-c, macos, xcode

从本章开始,我们会抛弃playgroup工程,转而采用Command Line Tool工程来实现专题中的例子。

类对象

用来抽象成一个通用类型 相关数据建模。

类的语法,使用关键字class来定义:class className { }

类的创建

一个简单的自定义类的例子

swift">// Monster.swiftimport Foundationclass Monster {var town: Town?var name = "Monster"func terrorizeTown() {if town != nil { //注意这种非空的判断方法print("\(name) is terrorizing a town!")} else {print("\(name) hasn't found a town to terrorize yet...")}}
}

类Monster的town属性为结构体,在swift中结构体和类差不太多。

swift">struct Town {var population = 5422var numberOfStoplights = 4func printDescription() {print("Population: \(population); number of stop lights: \(numberOfStoplights)")}mutating func changePopulation(by amount: Int) {population += amount}
}

类的实例化使用

swift">
// Main.swift
var myTown = Town();
let genericMonster = Monster()
genericMonster.town = myTown
genericMonster.terrorizeTown() //Monster is terrorizing a town!

类的继承

语法和objective-c一样,全是用:号,下面的 Zombie 类继承了 Monster 类。在这种继承中可以用self和super关键字。

swift">Zombie.swift
class Zombie: Monster {var walksWithLimp = true //增加了一个新属性//重写了父类的terrorizeTown方法,final表示再有子类时不允许再重写了final override func terrorizeTown() {town?.changePopulation(by: -10) //空链式调用,省去了if判断super.terrorizeTown()}
}

测试代码

swift">//Main.swift
let fredTheZombie = Zombie()
fredTheZombie.town = myTown
fredTheZombie.terrorizeTown() //Monster is terrorizing a town!
fredTheZombie.town?.printDescription() //Population: 5912; number of stop lights: 4

静态方法

在结构体中定义静态方法需要用到static关键字,在类中可以使用class和static两种关键字来标记,区别在于:

  • 用class关键字时,此时子类可以像普通方法一样复写父类的静态方法;
  • 用static关键字,此时子类不能复写了,有点类似final的作用;
swift">class Monster {class func makeSpookyNoise() -> String { //String表示参数return "Brains..."}static func makeSpookyNoise() -> String {return "Brains..."}
} let msn = Monster.makeSpookyNoise()

属性

类、结构体和枚举都可以有属性,属性分为存储和计算属性两种,前者可以有默认值,后者则会根据现有信息返回某种计算结果。可以监听属性的变化,也可以给属性设定一些规则。

属性的存储

就是通常所用let和var定义的变量,示例代码如下:

  • 普通的存储属性,只用于属性的简单存取
swift">//-----
class Monster {var town: Town?var name = "Monster"
}
  • 嵌套属性,即一个属性内部还有其它属性,比如枚举
swift">//------
struct Town {var population = 5_422 //这种表示方法同5422是一个意思var numberOfStoplights = 4enum Size {case smallcase mediumcase large}
}    

lazy惰性存储,使用才初始化

主要是为了节省内存,只在第一次被访问的时候才会真正初始化,使用关键字lazy var 。它可以引用闭包或函数,以实现依赖其它值来初始化属性的目的。

语法格式: lazy var propertiesName: Type = {}()

swift">struct Town1 {static let region = "South"enum Size {case smallcase mediumcase large}var population = 5_422//声明lazy属性townSize,类型为Size。然后定义一个闭包函数来计算此属性的真实值lazy var townSize: Size = {switch self.population {case 0...10_000:return Size.smallcase 10_001...100_000:return Size.mediumdefault:return Size.large}}()   //这里的()类似一个方法调用的方式,比如func()。
}//测试,这里需要注意即使更改了population的值,也调用了一次lazy属性,然而再手动更改population值时也不会自动更新townSize的值,因为它们并不是连动的。
var myTown1 = Town1()
let myTown1Size = myTown1.townSize
print(myTown1Size) //small

getter/setter属性计算

它不存储值,而是提供一个getter方法来获取属性的值,也可提供一个setter方法来设置属性的值。这种方式正好弥补了lazy属性不自动更新的弊端。

语法格式: var propertiesName: Type { get{} set(){} }

swift">struct Town {static let region = "South"var population = 5_422 { //这种用法叫观察都后面会讲didSet(oldPopulation) {print("The population has changed to \(population) from \(oldPopulation).")}}var numberOfStoplights = 4enum Size {case smallcase mediumcase large}var townSize: Size {get {switch self.population {case 0...10_000:return Size.smallcase 10_001...100_000:return Size.mediumdefault:return Size.large}}}func printDescription() {print("Population: \(population); number of stop lights: \(numberOfStoplights)")}mutating func changePopulation(by amount: Int) {population += amount}
}//测试
var myTown = Town()
let myTownSize = myTown.townSize
print(myTownSize) //smal//值会重新计算,相当于连动了
myTown.changePopulation(by: 1_000_000) //The population has changed to 1005422 from 5422.
print("Size: \(myTown.townSize); population: \(myTown.population)") //Size: large; population: 1005422

读取和写入方法

即同时声明getter和setter方法,实现属性的读取方法。

swift">class Zombie: Monster {override class var spookyNoise: String {return "Brains..."}var walksWithLimp = falseprivate(set) var isFallingApart = falsefinal override func terrorizeTown() {if !isFallingApart {town?.changePopulation(by: -10)}}
}
swift">class Monster {class var spookyNoise: String {return "Grrr"}static let isTerrifying = truevar town: Town?var name = "Monster"//这里~~var victimPool: Int {get {return town?.population ?? 0}set(newVictimPool) {town?.population = newVictimPool}}func terrorizeTown() {if let _ = town {print("\(name) is terrorizing a town!")} else {print("\(name) hasn't found a town to terrorize yet...")}}
}

测试代码

swift">var myTown = Town()
let fredTheZombie = Zombie()
fredTheZombie.town = myTown
fredTheZombie.terrorizeTown() //The population has changed to 5412 from 5422.
fredTheZombie.town?.printDescription() //Population: 5412; number of stop lights: 4print("Victim pool: \(fredTheZombie.victimPool)") //Victim pool: 5412
//设置值
fredTheZombie.victimPool = 500 //The population has changed to 500 from 5412.
print(Zombie.spookyNoise) //Brains...
print("Victim pool: \(fredTheZombie.victimPool)") //Victim pool: 500/*
The population has changed to 5412 from 5422.
Population: 5412; number of stop lights: 4
Victim pool: 5412
The population has changed to 500 from 5412.
Brains...
Victim pool: 500
*/

属性变化观察者

属性观察者会观察并响应给定属性的变化,它可以用于任何自定义的存储属性和任何继承的属性,但不能用于计算属性。

语法格式: var propertiesName: Type = value { diSet(oldV){} willSet(newV){} }

上述代码中在调用:fredTheZombie.terrorizeTown() 会改变population属性的值,此时就可以用didSet来观察值,切入一次操作。

  • diSet:已经发生变化,针对old值
  • willSet:即将发生变化,针对new值
swift">struct Town {static let region = "South"var population = 5_422 {didSet(oldPopulation) {print("The population has changed to \(population) from \(oldPopulation).")}}
}    //下面的代码就会触发didSet
fredTheZombie.victimPool = 500

静态不可变属性

swift中又称为类型属性,即不能过实例就可直接访问。所有的类型属性必须有默认值,可简单理解为swift中的类型属性就是java中的final类型。

  • 结构体中使用
swift">struct Town {static let region = "South"
}
  • 类的类型属性
swift">class Monster {class var spookyNoise: String {return "Grrr"}static let isTerrifying = true
}    
//测试
print(Monster.region)
print(Monster.isTerrifying)

这个例子中使用了计算属性,所以在子类中可以允许再覆写的,但需要用到关键字override。在子类中覆写:

swift">class Zombie: Monster {//覆写override class var spookyNoise: String {return "Brains..."}
}

访问作用域控制

有时候,我们希望程序的某部分代码对其他部分不可见。事实上,对代码访问有细粒度的控制是常见需求。我们可以给某些组件访问其他组件的一定级别的访问权限,这被称为访问控制(access control)。

访问控制是围绕着模块和源代码而言的,在Swift中提供了5种访问控制符号

访问层级描述对…可见能在…继承
open实体对模块内的所有文件以及引入了此模块的文件都可见,并且可以继承实体所在的模块及引入、实体所在模块的模块实体所在的模块及引入、实体所在模块的模块
public对模块内的所有文件以及引入了此模块的文件都可见实体所在的模块及引入、实体所在模块的模块实体所在模块
internal(默认)实体对模块内的所有文件可见实体所在模块实体所在模块
fileprivate实体只对所在的源文件可见实体所在的文件实体所在的文件
private实体只对所在的作用域可见所在的作用域所在的作用域

修饰属性示例

下面是一个简单的示例:

swift">private var isFallingApart = false

修饰属性读写方法的示例,这里的set可有可无,如果设置了set则说明private只对set方法有效,而get方法则采用默认修饰符,所以为了麻烦一般都不指定set。get和set是自定义的方法函数名。

swift">class Zombie: Monster {override class var spookyNoise: String {return "Brains..."}var walksWithLimp = falseprivate(set) var isFallingApart = falsefinal override func terrorizeTown() {if !isFallingApart {town?.changePopulation(by: -10)}}
}

http://www.ppmy.cn/devtools/15908.html

相关文章

Python打怪升级(4)

在计算机领域常常有说"合法"和"非法"指的是:是否合理,是否有效,并不是指触犯了法律。 random.randint(begin,end) 详细讲解一下这个random是指模板,也就是别人写好的代码直接来用,在Python当中,…

架构师系列-消息中间件(九)- RocketMQ 进阶(三)-消费端消息保障

5.2 消费端保障 5.2.1 注意幂等性 应用程序在使用RocketMQ进行消息消费时必须支持幂等消费,即同一个消息被消费多次和消费一次的结果一样,这一点在使用RoketMQ或者分析RocketMQ源代码之前再怎么强调也不为过。 “至少一次送达”的消息交付策略&#xff…

人工智能与汽车行业的定量分析研究

人工智能与汽车行业的定量分析研究 摘要:[论文摘要] 关键词:[论文关键词] 一、引言 随着科技的飞速发展,人工智能(AI)技术已经深入到各个行业领域,汽车行业亦不例外。AI与汽车行业的结合,不…

通过一系列vue-demo入门vue2

一、创建简单vue实例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible&…

基础SQL DML-插入语句

插入语句前&#xff0c;我们先创建一个表。表的创建在DDL语句里面涉及&#xff0c;可以参考&#xff1a;小赖同学吖-CSDN博客 我们创建一个员工表进行数据的插入操作 插入&#xff08;添加&#xff09;语句的语法 给员工表添加一条记录 给员工表添加多条记录 也可以通过下面的方…

基于B2C的网上拍卖系统——秒杀与竞价

点击下载源码和论文https://download.csdn.net/download/liuhaikang/89222887 课题背景及意义 随着网络的进一步普及和电子商务的高速发展&#xff0c;越来越多的人们开始在网络中寻求方便。网上网物具备了省时、省事、省心、高效等特点&#xff0c;从而受到越来越多人的欢迎。…

脚手架搭建项目package.json配置中依赖的版本问题

脚手架搭建项目package.json配置中依赖的版本问题 问题描述&#xff1a;项目刚搭建好&#xff0c;运行没有问题&#xff0c;为什么过一段时间&#xff0c;删除node_modules&#xff0c;或者重新安装包依赖&#xff0c;然后项目某些地方出现莫名的错误&#xff08;依赖库的地方…

Node.js身份核验接口、身份证二、三要素实名认证接口

随着互联网的高速发展&#xff0c;人们可以发表言论的渠道越来越多。网络平台不断汲取各地、各人、各时发表的各种信息。人们喜欢将信息发布到微博、知乎、天涯、豆瓣等等网络平台&#xff0c;逐步的&#xff0c;网络信息进入大爆炸时代。这些大量涌现的信息中难免掺杂着一些不…

10:00面试,10:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

CTF网络安全大赛详情

网络安全已成为现代社会的一个关键挑战&#xff0c;随着互联网技术的飞速发展&#xff0c;从个人隐私保护到国家安全&#xff0c;网络安全的重要性日益突显。为了应对这一挑战&#xff0c;CTF&#xff08;Capture The Flag&#xff0c;中文&#xff1a;夺旗赛&#xff09;应运而…

手写一个民用Tomcat (06)

我们这次是引入获取参数&#xff0c;比如你的GET 请求 或者post 请求 如何吧请求参数进行封装 成map 集合 。 先看下erquest。请求类里边改造 private void parseRequestLine() 这个方法 改造成 依据 ?进行分割处理因为 http://localhost:8080/servlet/com.yixin.HelloWor…

Ubuntu系统安装配置笔记

最近装了台Ubuntu系统用于日常工作&#xff0c;过程中搜索了很多资料或找ChatGPT解答疑问&#xff0c;已有的资料都比较详细了&#xff0c;因此这篇笔记主要是列举大纲和参考网站&#xff0c;并记录中间踩坑耗时较多的问题。 一&#xff0c;系统安装 1&#xff0c;镜像下载 …

完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城

源码下载地址&#xff1a;完美运营版商城.zip 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本

如何快速学习盲打键盘的指法

学习盲打键盘的指法需要一定的时间和练习&#xff0c;但是以下几个方法可以帮助你加快学习的速度&#xff1a; 掌握正确的手位&#xff1a;了解标准的键盘布局以及手指应该放置的位置是学习盲打的第一步。在QWERTY键盘上&#xff0c;你的左手应该放在ASDF键上&#xff0c;右手应…

车载以太网DoIP 协议,万字长文详解

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

【Node.js】02 —— Path模块全解析

&#x1f31f;Node.js之Path模块探索&#x1f308; &#x1f4da;引言 在Node.js的世界中&#xff0c;path模块就像一把万能钥匙&#x1f511;&#xff0c;它帮助我们理解和操作文件与目录的路径。无论你是初入Node.js殿堂的新手&#xff0c;还是久经沙场的老兵&#xff0c;理…

卡口车辆智能检索系统

卡口车辆智能检索系统是基于海量卡口图像和视频数据&#xff0c;通过智能化的信息挖掘、模式匹配及快速搜索等智能图像处理技术&#xff0c;完成车辆、车型、车身颜色、车辆特征、相似车辆搜索等核心业务功能&#xff0c;扩展基于治安卡口数据的应用手段。 卡口车辆智能检索系…

在【laravel框架】学习中遇到的常见的问题以及解决方法

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【设计模式】享元模式

目录 什么是享元模式 代码实现 什么是享元模式 Java中的享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它用于减少系统中对象的数量&#xff0c;以节省内存和提高性能。享元模式通过共享相似对象之间的公共部分来最小化内存使用。 在享…

react之组件与JSX

第一章 - 描述用户界面 概述&#xff1a;React是一个用于构建用户界面&#xff08;UI&#xff09;的JavaScript库&#xff0c;用户界面由按钮&#xff0c;文本和图像等小单元内容构建而成。React帮助你把它们组合成可重用&#xff0c;可嵌套的组件。从web端网站到移动端应用&a…