swift基础语法

news2024/12/26 13:41:21

swift学习笔记

参考教程

https://www.runoob.com/swift/swift-data-types.html

swift代码规范

https://juejin.cn/post/7129465308376465422

1 环境搭建

必须要有苹果电脑且安装Xcode

2 基本语法

Swift是类型安全的语言,编译时会进行类型检查

import Cocoa
var mySting = "Hello, World!"
print(myString)

2.1 引入

可以使用import语句引入任何的Objective-C(C语言的严格超集)

  • 创建macOS playground则引入Cocoa,Cocoa由Objective-C语言写成,因此可以混入C语言代码,甚至C++代码
  • 创建iOS playground则引入UIKit

2.2 注释

// 这是单行注释(单行注释以//开头)

/* 多行注释
多行注释(以/*开始,以*/结束,可以嵌套单行注释)*/

2.3 分号

Swift不要求每行结尾使用分号,但在同一行书写多条语句必须用分号隔开

import Cocoa
var myString = "Hello, World!"; print(myString)

2.4 标识符

标识符是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字

  • 区分大小写
  • 可以以字母或下划线开头,但不能以数字开头
  • 标识符中的其他字符可以是字母、数字或下划线,不能是关键字

Swift使用Unicode编码,可以使用中文,甚至聊天表情符

import Cocoa
// 如果一定要使用关键字作标识符,可以在关键字前后加`
let `class` = "Runoob"

2.5 关键字

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.6 空格

Swift语言并不是像C/C++,Java那样完全忽视空格,Swift对空格的使用有一定的要求,但是又不像Python对缩进的要求那么严格。在Swift中,运算符不能直接跟在变量或常量的后面。

import Cocoa
// 错误1:let a= 1+ 2
// 错误2:let a = 1+ 2

let a = 1 + 2
let b = 3+4  // 这样写是可以的

为避免错误,尽量严格缩进

2.7 打印输出

import Cocoa
print("Runoob")  // 使用print函数输出,如果多个print,默认换行输出
// 如果不想换行则将terminator设置为空字符串,这样每个输出以空格分隔
for x in 0...10 {  // 这是循环语句,后续会介绍
  print("\(x)", terminator: "")  // \()可以将x变为字符串
}

// 如果接收用户的输入使用readLine()
let theInput = readLine()

3 数据类型

3.1 内置数据类型

  • Int:整型,在32位平台上和Int32长度相同,在64位平台上和Int64长度相同
  • UInt:无符号整型,在32位平台上和UInt32长度相同,在64位平台上和UInt64长度相同(尽量不要使用UInt,统一使用Int可以提高代码的可复用性)
  • Float:32位浮点数,精度较低,至少有6位数字
  • Double:64位浮点数,精度很高,至少有15位数字
  • Bool:布尔值,有true、false和nil(表示没有值)
  • String:字符串,是字符的序列集合,用双引号引起来
  • Character:字符,单个字母,用双引号引起来
  • Optional:可选类型,表示有值或没有值
    在这里插入图片描述

3.1.1 字符串

1.字符串的创建:使用字符串字面量或String类实例子创建字符串

import Cocoa

// 使用字符串字面量创建字符串
var stringA = "Hello, World"
print(stringA)

// 使用String类的实例创建字符串
var stringB = String("Hello, World!")
print(stringB)

2.空字符串,可以使用字符串属性isEmpty判断字符串是否为空

import Cocoa

// 使用字符串字面量创建空字符串
var stringA = "" 
if stringA.isEmpty {
  print("stringA是空的")
} else {
  print("stringA不是空的")
}

// 使用String类的实例创建空字符串
var stringB = String()
if stringB.isEmpty {
  print("stringB是空的")
} else {
  print("stringB不是空的")
}

3.字符串插值:在字符串中使用反斜线和括号插入变量

import Cocoa
var age: Int = 24
print("My age is \(age)")

4.字符串连接:使用加号连接

import Cocoa
let constA = "Hello, "
let constB = "World!"
var stringComb = constA + constB
print(stringComb)

5.字符串长度:使用count属性计算

import Cocoa
var varA = "Hello, World!"
print("\(varA)的长度为\(varA.count)")  // 输出为13

6.字符串比较:使用==比较两个字符串是否相同

7.Unicode字符串:String是基于Unicode建立的,可以循环迭代出字符串中的UTF-8和UTF-16的编码

import Cocoa
var unicodeString = "Hello, World!"
for code in unicodeString.utf8 {
  print(code)
}

for code in unicodeString.utf16 {
  print(code)
}

8.字符串分割成数组

import Cocoa

let fullName = "First Last"
let fullNameArr = fullName.split{" "}.map(String.init)

fullNameArr[0] // First
fullNameArr[1] // Last

在这里插入图片描述
在这里插入图片描述

3.1.2 字符

1.空字符:swift不能创建空字符常量或变量

2.遍历字符串中的字符

import Cocoa
for ch in "Hello, World!" {
  print(ch)
}

3.字符串连接字符:使用String的append()方法

import Cocoa
var varA: String = "Hell"
var varB: Character = "o"

varA.append(varB)
print(varA)

3.2 类型别名

// 使用typealias关键字定义
import Cocoa
typealias Feet = Int  // 定义类型别名
var distance: Feet = 100
print(distance)

3.3 类型推断

如果没有显示的制定类型,Swift会根据初始值进行类型推断

import Cocoa
let meaningOfLife = 42  // meaningOfLife被推断为Int类型
let pi = 3.1415  // pi被推断为Double类型,而非Float类型
let anotherPi = 3 + 0.1415  // anotherPi被推断为Double类型

4 变量

4.1 变量声明

使用var关键字来声明

import Cocoa
// 方式一:
var varA: Int
varA = 42

// 方式二:
var varB: Double = 3.14

4.2 变量命名

  • 变量名可以由字母、数字和下划线组成
  • 变量名需要以字母或下划线开始
  • 变量名区分大小写
  • 变量名可以使用Unicode
import Cocoa
var 你好 = “你好”
print(你好)

4.3 变量输出

  • 变量和常量使用print函数输出
  • 字符串差值输出:在字符串中使用反斜线和括号插入变量
import Cocoa
var age: Int = 24
print("My age is \(age)")

5 可选类型

Optional:可选类型,用于处理值缺失情况,表示可能有或可能没有值

当声明一个可选变量或者可选属性时没有提供初始值,则默认为nil

// 声明方式
// 方式一:
var optionalInteger1: Int?  // 类型和?之间没有空格
// 方式二:
var optionalIneger2: Optional<Int>

// 强制解析:如果一个可选类型的实例包含一个值,可以用后缀!来访问这个值,如果可选类型为nil,使用!运行时会报错
optionalInteger1 = 42
print(optionalInteger1!)  // 强制解析

// 自动解析:在声明可选变量时使用!替代?,后续再获取该值时不需要!强制解析
var myString: String!
myString = "Hello, World!"
print(myString)

可选绑定:判断可选类型是否包含值,如果包含就把值赋给一个临时常量或变量,用在if和while语句

import Cocoa
var myString: String?
myString = "Hello World!"
if let yourString = myString {
	print("你的字符串的值为:\(yourString)")
} else {
  print("你的字符串没有值"}

6 常量

6.1 常量声明

常量类似于变量,区别在于常量的值一旦设定就不能改变,而变量的值可以随意更改,使用let关键字来声明

import Cocoa
let constA = 42
print(constA)

6.2 类型标注

import Cocoa
let constB: Double = 3.14
print(constB)

6.3 常量命名

和变量的命名规则相同,同4.2

6.4 常量输出

和变量的输出方式相同,同4.3

7 字面量

7.1 整型字面量

二进制前缀为0b,八进制前缀为0o,十六进制前缀为0x,十进制没有前缀

let decimalInteger = 17  // 十进制17
let binaryInteger = 0b100001  // 二进制17
let octalInteger = 0o21  // 八进制17
let hexadecimal = 0x11  // 十六进制17

7.2 浮点型字面量

let decimalDouble = 12.1e2  // 十进制浮点型字面量:12.1*10^2
let hexadecimalDouble = 0xC.3p3  // 十六进制浮点型字面量:12.3*2^3

7.3 字符串型字面量

字符串型字面量中不能包含未转义的引号,未转义的反斜线、回车符或换行符

在这里插入图片描述

7.4 布尔型字面量

  • true表示真
  • false表示假
  • nil表示没有值

8 运算符

8.1 算术运算符

+、-、*、/、%

Swift中已经取消了++和–

8.2 比较运算符

==、!=、>、<、>=、<=

8.3 逻辑运算符

  • &&:逻辑与
  • ||:逻辑或
  • !:逻辑非

8.4 位运算符

对二进制位进行操作

  • &:按位与
  • |:按位或
  • ^:按位异或,输入数同一位不同为1,相同为0
  • ~:按位取反
  • <<:按位左移,左移后左边的数位被丢弃,右边的空位用0填充
  • >>:按位右移,右移后右边的数位被丢弃,左边的空位用0填充

8.5 赋值运算符

=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=

8.6 区间运算符

  • a…b:闭区间运算符,定义一个从a到b(包括a和b)所有值的区间
  • a…<b:开区间运算符,定义一个从a到b但不包含b的所有值的区间

8.7 其他运算符

  • a ? b : c 三目运算符,如果a为true值为b,否则为c
  • ?? 合并空值运算符,例如a ?? b,如果a有值则展开,如果没有值(nil),则返回b。其中表达式a必须是可选类型,表达式b必须与a的存储类型相同

8.8 运算符优先级

原则

  • 指针最优,单目运算符优于双目运算符
  • 先乘除后加减
  • 先算数运算符,后移位运算符,最后位运算符
  • 逻辑运算符最后计算

9 条件语句

在这里插入图片描述

10 循环语句

在这里插入图片描述
在这里插入图片描述

11 数组

如果创建一个数组,并赋值给一个变量,则创建的集合可添加、删除、修改,如果赋给常量则数组不可更改

11.1 创建数组

import Cocoa
// 1. 创建Int类型的空数组变量
// 法一:(推荐)
var someInts1: [Int] = []
// 法二
var someInts2 = [Int]()

// 2. 创建数量为3,初始值为0的Int类型数组
var someInts3 = [Int](repeating: 0, count: 3)

// 3. 创建含有3个元素的数组
var someInts4: [Int] = [10, 20, 30]  // 必须用逗号隔开,不能只用空格隔开

11.2 访问数组

// 通过索引获取数组值:索引下标从0开始
import Cocoa
var someInts = [Int](repeating: 10, count: 3)
var someVar: Int = someInts[0]
print(someVar)

11.3 修改数组

import Cocoa
// 1. 数组末尾添加元素:append()方法或+=
var someInts: [Int] = []
someInts.append(10)
someInts += [20]
print(someInts[0])
print(someInts[1])

// 2. 通过索引修改数组元素值
someInts[1] = 30
print(someInts[1])

11.4 遍历数组

import Cocoa
// 使用for-in循环遍历数组
var someStrs: [String] = ["Hello", "World"]
for item in someStrs {
  print(item)
}

11.5 合并数组

// 可以使用+合并两种已存在的相同类型数组
import Cocoa
var intA = [Int](repeating: 2, count: 2)
var intB = [Int](repeating: 1, count: 3)
var intC = intA + intB
for item in intC {
  print(item)
}

11.6 属性

import Cocoa
// 1. count属性:统计数组元素个数
var intA = [Int](repeating: 2, count: 2)
var intB = [Int](repeating: 1, count: 3)
var intC = intA + intB
print(intC.count)

// 2. isEmpty属性:判断数组是否为空,如果为空返回true,不为空返回false
var varA: [Int] = []
var varB: [Int] = [1, 2, 3]
print(varA.isEmpty)
print(varB.isEmpty)

12 字典

  • 字典用来存储无序相同类型数据的集合。
  • 字典中每个值(value)都有关联唯一的键(key),键是值的标识符,通过键访问值,键的类型没有限制但必须唯一
  • 同数组一样,如果创建的字典赋值给变量则字典可以修改,赋值给常量则不可修改

12.1 创建字典

import Cocoa
// 1. 创建一个空字典,键的类型为Int,值的类型为String
// 法一(推荐):
var someDict1: [Int: String] = [:]
// 法二:
var someDict2 = [Int: String]()

// 2. 创建字典实例:注意冒号前无空格,冒号后有空格
var someDict3: [Int: String] = [1: "one", 2: "two"]  

12.2 访问字典

import Cocoa
// 根据字典的键来访问值
var someDict: [Int: String] = [1: "one", 2: "two"]  
var varA: String? = someDict[1]  // 注意如果标注类型,必须是可选类型
var varB = someDict[2]  // varB也是可选类型
print(varA!)
print(varB!)

12.3 修改字典

// 使用updateValue(, forKey: )增加或更新字典内容,如果key不存在,则添加该键值,如果key存在则修改对应的value,该方法返回原来旧的value的Optional类型值
import Cocoa
var someDict: [Int: String] = [1: "One", 2: "Two"]
var oldVal = someDict.updateValue("One 新的值", forKey: 1)  
var newVal = someDict[1]  

print(oldVal)  // oldVal值为Optional("One")
print(newVal)  // newVal值为Optional("One 新的值")

12.4 移除Key-Value对

// 法一:使用removeValue(forKey: ),返回Value的Optional类型值,如果不存在返回nil
import Cocoa
var someDict: [Int: String] = [1: "One", 2: "Tow", 3: "Three"]
var removeValue1 = someDict.removeValue(forKey: 2)  
var removeValue2 = someDict.removeValue(forKey: 4)

print(removeValue1)  // removeValue1值为Optional("Tow")
print(removeValue2)  // removeValue2值为nil

// 法二:也可以通过指定键的值为nil来移除键值对
someDict[1] = nil
print(someDict[1])  // nil

12.5 遍历字典

import Cocoa
var someDict: [Int: String] = [1: "One", 2: "Tow", 3: "Three"]

// 法一:使用for-in循环遍历
for (key, value) in someDict {
  print("键\(key)对应的值为\(value)")
}
// 键2对应的值为Tow
// 键1对应的值为One
// 键3对应的值为Three

// 法二:使用enumerated()遍历,返回的是字典的索引以及键值对
for (key, value) in someDict.enumerated() {  // key是索引,value是键值对
  print("索引\(key)对应的键值对为\(value)")
}
// 索引0对应的键值对为(key: 2, value: "Tow")
// 索引1对应的键值对为(key: 1, value: "One")
// 索引2对应的键值对为(key: 3, value: "Three")

12.6 字典转换成数组

// 使用字典的keys属性和values属性将键和值分别转变为数组
import Cocoa
var someDict: [Int: String] = [1: "One", 2: "Tow", 3: "Three"]
let dictKeys = [Int](someDict.keys)
let dictValues = [String](someDict.values)
// 以下是错误写法!!!
// let dictKeys: [Int] = someDict.keys
// let dictValues: [String] = someDict.values

for key in dictKeys {
  print(key)
}
// 2
// 3
// 1

for value in dictValues {
  print(value)
}
// Tow
// Three
// One

12.7 常用属性

import Cocoa
var someDict1: [Int: String] = [1: "One", 2: "Tow", 3: "Three"]
// 属性一:count属性统计键值对的个数
print(someDict1.count)  // 3
// 属性二:isEmpty判断字典是否为空,空为true,不空为false
var someDict2: [Int: String] = [:]
print(someDict2.isEmpty)  // true

13 函数

13.1 函数定义

  • 使用func关键字定义
  • 可指定0个、一个或多个输入参数和一个返回值类型
  • 函数的实参传递顺序必须与形参列表相同,->后为函数的返回值类型
// 形式
// func funcname(形参名: 形参类型) -> returnType {
// 	...
// 	return ...
// }

import Cocoa
func cityHello(city: String, hello: String) -> String {
  return city + " " + hello
}
print(cityHello(city: "北京", hello: "你好!"))  // 注意city和hello不能省略

13.2 函数参数

  • 局部参数名:只能在函数体内部使用
import Cocoa
// city和hello是局部参数
func cityHello(city: String, hello: String) -> String {
  return city + " " + hello
}
print(cityHello(city: "北京", hello: "你好!"))
  • 外部参数名:在局部参数名前加外部参数名,再函数被调用时,必须使用外部参数名
import Cocoa
func printFunc(agrv hello: String) {
  print("北京 \(hello)")
}
printFunc(argv: "你好")
// 忽略外部参数名
import Cocoa
func printFunc(_ hello: String) {
  print("北京 \(hello)")
}
printFunc("你好")
  • 可变参数:可以接受另个或多个参数,通过在变量类型后加…定义
import Cocoa
func vari<Int>(members: N...){
  for i in members { print(i) }
}
vari(members: 3, 4, 5)
vari(members: 3.1, 4.1, 5.1)
vari(members: "你好", "北京")

13.3 值传递与引用传递

  • 函数中的参数默认都是常量,只能查看,不能修改。
  • 如果想要声明变量参数,进行引用传递,需要在参数类型前加inout关键字。且在调用时加&
import Cocoa
func swapFunc(_ a: inout Int, _ b: inout Int) {
  var temp = a
  a = b
  b = temp
  print("参数1在函数中的值为\(a),参数2在函数中的值为\(b)")  // 2, 1
}
var x = 1
var y = 2
swapFunc(&x, &y)
print("参数1在函数外的值为\(x),参数2在函数外的值为\(y)")  // 2, 1

13.4 函数返回值

元组作为返回值

  • 元组与数组类似,不同的是,元组中的元素可以是任意类型,使用圆括号
  • 可以使用元组类型让多个值作为一个复合值从函数中返回
// 定义一个函数,实现找到Int数组的最小值和最大值
import Cocoa
func minMax(array: [Int]) -> (min: Int, max: Int) {
  var currentMin = array[0]
  var currentMax = array[0]
  for value in array[1..<array.count] {
    if value < currentMin {
      currentMin = value  // 和C/C+不同的是尽管只有一条语句,也不能不加大括号和if写在一行
    }
    if value > currentMax {
      currentMax = value
    }
  }
  return (currentMin, currentMax)
}
let array: [Int] = [1, 2, 3, 4]
let val = minMax(array: array)
print("array的最小值为\(val.min),array的最大值为\(val.max)")
  • 如果不确定返回的元组一定不为nil,则可以返回一个可选元组类型,例如(Int, Int)?,注意与(Int?, Int?)不同,(Int, Int)?整个元组是可选的,不只是元组中的每个元素值。上面找最小值和最大值的函数,如果传入的array为空,则应该返回nil
import Cocoa
func minMax(array: [Int]) -> (min: Int, max: Int)? {
  if array.isEmpty { return nil }
  var currentMin = array[0]
  var currentMax = array[0]
  for value in array[1 ..< array.count] {
    if value < currentMin { currentMin = value} 
    if value > currentMax { currentMax = value}
  }
  return (min: currentMin, max: currentMax)
}
let array: [Int] = [1, 2, 3, 4, 5]
if let val = minMax(array: array) {
  print("array的最小值为\(val.min),array的最大值为\(val.max)")
}

没有返回值函数

  • 只需要去掉 -> return type
import Cocoa
func printFunc(hello: String) {
  print("北京 \(hello)")
}
printFunc(hello: "你好")

13.5 函数类型

  • 函数类型与其他类型类型,可以定一个类型为函数的常量或变量
import Cocoa
func sum(a: Int, b: Int) -> Int {
  return a + b
}
var add: (Int, Int) -> Int = sum  // 定义一个名为add的函数变量,该变量的参数类型和返回值都为Int,并将这个变量指向sum函数
print(add(1, 2))  // 输出3,注意不要加a和b
print(sum(a: 1, b: 2))  // 输出3,注意要加a和b

13.6 函数嵌套

函数嵌套指的是函数内定义一个新的函数,外部函数可以调用函数内定义的函数

14 闭包

14.1 定义与语法

  • 定义:闭包是自包含的功能代码块,可以在代码中使用或者用来作为参数传值,和匿名函数类似

  • 形式:

    • 全局函数:有名字但不能捕获任何值
    • 嵌套函数:有名字也能捕获封闭函数内的值
    • 闭包表达式:无名闭包,使用轻量语法,根据上下文环境捕获值
  • 语法

{(parameters) -> return type in
   statements
}
import Cocoa
let divide = {(val1: Int, val2: Int) -> Int in
	return val1 / val2
}
print(divide(200, 20))

14.2 闭包表达式

  • sorted方法:会根据用于排序的闭包函数对数组中的值进行排序,该方法返回一个与原数组长度大小相同且排序正确的新数组,原数组不会被更改。
  • sorted方法需要传入两个参数
    • 已知类型的数组
    • 闭包函数:传入两个与数组元素类型相同的两个值,返回布尔值

全局函数

import Cocoa
let num: [Int] = [2, 3, 1, 4]

// 使用全局函数提供排序,闭包函数类型为(Int, Int) -> Bool
func backwards(val1: Int, val2: Int) -> Bool {
	return val1 > val2	// 从大到小排列
}
var reversed = num.sorted(by: backwards)
print(reversed)  // [4, 3, 2, 1]

参数名称缩写

import Cocoa
let num: [Int] = [2, 3, 1, 4]
// swift自动为内联函数提供了参数名称缩写功能,可以直接通过$0,$1顺序调用闭包参数
var reversed = num.sorted(by: { $0 > $1 })
print(reversed)  // [4, 3, 2, 1]

运算符函数

import Cocoa
let num: [Int] = [2, 3, 1, 4]
// 使用运算符排序
var reversed = num.sorted(by: >)
print(reversed)  // [4, 3, 2, 1]

尾随闭包

import Cocoa
let num: [Int] = [2, 3, 1, 4]
// sorted()后的{ $0 > $1 }为尾随闭包
var reversed = num.sorted() { $0 > $1 }
print(reversed)  // [4, 3, 2, 1]

14.3 捕获值

  • 闭包可以在其定义的上下文中捕获常量或变量
  • swift最简单的闭包是嵌套函数,即定义在其他函数内的函数,嵌套函数可以捕获其外部函数所有的参数及定义的常量和变量
import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
  var runningTotal = 0
  func incrementor() ->Int {
    runningTotal += amount
    return runningTotal
  }
  return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
print(incrementByTen())  // 10
print(incrementByTen())  // 20
print(incrementByTen())  // 30
  • 上面例子尽管incrementByTen是一个常量,但这个常量指向的闭包仍可以增加其捕获的变量值,因为函数和闭包都是引用类型。
  • incrementByTen指向闭包的引用是一个常量,并非闭包本身是常量。因此如果将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包
import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
  var runningTotal = 0
  func incrementor() ->Int {
    runningTotal += amount
    return runningTotal
  }
  return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
print(incrementByTen())  // 10
print(incrementByTen())  // 20
print(incrementByTen())  // 30
// 
let alsoIncrementByTen = incrementByTen
print(alsoIncrementByTen())  // 40

15 枚举

15.1 定义与语法

  • 定义:一种数据类型,只包含自定义的特定数据,是一组有共同特性的数据集合,声明在中,通过实例化类来访问值
  • 语法:使用enum和case关键词来创建枚举
  • 注意:swift的枚举成员在创建时不会被赋予整型值
  • 枚举、结构体、类的标识符(即名称)一般采用大驼峰(即第一个单词的首字母大写)
import Cocoa
enum DaysofWeek {  
  case Sunday
  case Monday
  case Tuesday
  case Wednesday
  case Thursday
  case Friday
  case Saturday
}
var weekDay = DaysofWeek.Thursday
weekDay = .Friday 

15.2 相关值与原始值

在这里插入图片描述

相关值:可以是不同类型

import Cocoa
enum Student {
  case Name(String)
  case Mark(Int, Int, Int)
}
var studMarks = Student.Mark(1, 2, 3)
switch studMarks {
  case .Name(let studName):
  	print("学生的名字是\(studName)")
  case .Mark(let mark1, let mark2, let mark3):
  	print("学生的成绩是\(mark1)\(mark2)\(mark3)")
}

// 输出:学生的成绩是1、2、3

原始值:可以是整型、符点型、字符或字符串值。每个原始值在枚举声明中唯一。在原始值为整数枚举时,不需要显示的为每个成员赋值,swift会自动赋值,隐式赋值依次递增1,如果第一个值没有被赋处置,将会被自动设置为0

import Cocoa
enum Month: Int {
  case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
let yearMonth = Month.May.rawValue
print("月份为:\(yearMonth)")  // 月份为:5

16 结构体

16.1 语法

  • 通过struct关键字定义,可以定义属性和方法。结构体允许我们创建一个单一文件,且系统会自动生成面向其他代码的外部接口
import Cocoa
struct MarkStruct {
  var mark: Int
  
  init(mark: Int) { self.mark = mark }
}
var aStruct = MarkStruct(mark: 99)
var bStruct = aStruct
bStruct.mark = 100
print(aStruct.mark)  // 99
print(bStruct.mark)  // 100

16.2 应用

应用场景

  • 几何形状的大小:封装一个width属性和height属性,两者均为Double类型
  • 一定范围内的路径:封装一个start属性和length属性,两者均为Int类型
  • 三维坐标系内一点:封装x,y和z属性,三者均为Double类型

注意:结构体实例是通过值传递而不是引用

17 类

类可以定义属性和方法,和其他语言不同,swift不要求为自定义类去创建独立的接口和实现文件,只需要在一个单一文件中定义一个类,系统会自动生成面向其他代码的外部接口

import Cocoa
class MarkClass {
  var mark: Int
  init(mark: Int) { self.mark = mark }
}

let marks = MarkClass(mark : 100)
print("成绩为\(marks.mark)")

17.1 类和结构体对比

共同点:

  • 定义属性用于存储值
  • 定义方法用于提供功能
  • 定义附属脚本用于访问值?
  • 定义构造器用于生成初始化值
  • 通过扩展以增加默认实现的功能?
  • 符合协议以对某类提供标准功能?

与结构体相比,类还有如下的附加功能

  • 继承:允许一个类继承另一个类的特征
  • 类型转换:允许在运行时检查和解释一个类实例的类型?
  • 解构器:允许一个类实例释放任何其所被分配的资源
  • 引用计数:允许对一个类的多次引用

17.2 恒等运算符

类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例

在这里插入图片描述

import Cocoa

class SampleClass {
  let myProperty: String
  init(s: String) { myProperty = s }
}
let spClass1 = SampleClass(s: "Hello")
let spClass2 = SampleClass(s: "Hello")
if spClass1 === spClass2 { print("引用相同的类实例") }
if spClass1 !== spClass2 { print("引用不同的类实例") }

18 属性

属性可分为存储属性和计算属性

在这里插入图片描述

18.1 存储属性

存储属性是存储在特定类或结构体的实例里的一个常量或变量,可以在定义存储属性的时候指定默认值,也可以在构造过程中设置或修改存储属性的值

import Cocoa
struct Number {
  var digits: Int
  let pi = 3.14  // 定义存储属性的时候指定默认值
}
var n = Number(digits: 123)  // 构造过程中设置存储属性的值
n.digits = 1234  // 不会报错,构造过程中修改存储属性的值
// n.pi = 3.141  // 会报错,因为pi是常量
print(n.digits)  // 1234
print(n.pi)  // 3.14

18.2 延迟存储属性

延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性,必须将延迟存储属性声明为变量(var关键词),因为常量属性在构造完成之前必须要有初始值。延迟存储属性常用于延时对象的创建、属性的值依赖于其他未知类。

import Cocoa
class Sample {
  lazy var no = Number()  // lazy定义延迟存储属性,且该属性为var
}
class Number {
  var name = "world"
}
var firstSample = Sample()
print(firstSample.no.name)

18.3 计算属性

计算属性不直接存储值,而是提供一个get来获取值,一个可选的set来设置其他属性或变量的值

import Cocoa

class Sample {
  var no1 = 0.0, no2 = 0.0
  var length = 300.0, breadth = 150.0
  var middle: (Double, Double) {
    get { return (length / 2, breadth / 2) }
    set(axis) {
      no1 = axis.0 - (length / 2)
      no2 = axis.1 - (breadth / 2)
    }
  }
}
var result = Sample()
print(result.middle)
result.middle = (0.0, 10.0)  // (150.0, 75.0)
print(result.no1)  // -150.0
print(result.no2)  // -65.0

18.4 只读计算属性

只有get没有set的计算属性为只读计算属性

import Cocoa
class Film {
  var head = ""
  var duration = 0.0
  var metaInfo: [String: String] {
    return [
      "head": self.head,
      "duration": "\(self.duration)"
    ]
  }
}
var move = Film()
move.head = "Swift 属性"
move.duration = 3.09

print(move.metaInfo["head"]!)  // Swift 属性
print(move.metaInfo["duration"]!)  // 3.09

18.5 属性观察器

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性添加属性观察器。不需要为无法重载的计算属性添加属性观察器,因为可以通过set直接监控和响应值的变化。(用willSet和didiSet实现属性观察器)

import Cocoa
class Sample {
  var counter: Int = 0 {
    // 先执行willSet,再执行didSet
    willSet(newTotal) { print("计数器:\(newTotal)") }
    didSet {
      if counter > oldValue { print("新增数:\(counter - oldValue)") }  // oldValue为counter的旧值
    }
  }
}
let newCounter = Sample()
newCounter.counter = 100
newCounter.counter = 800

// 结果为:
// 计数器:100
// 新增数:100
// 计数器:800
// 新增数:700

18.6 类型属性

和实例属性区分开,类型属性是类型定义的一部分写在类型最外层的花括号里,使用关键字static定义值类型的类型属性,class定义类类型的类型属性

import Cocoa

struct StudMarks {
  static let markCount = 97
  static var totalCount = 0
  var InternalMarks: Int = 0 {
    didSet {
      if InternalMarks > StudMarks.markCount {
        InternalMarks = StudMarks.markCount
      }
      if InternalMarks > StudMarks.totalCount {
        StudMarks.totalCount = InternalMarks
      }
    }
  }
}

var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()

stud1Mark1.InternalMarks = 98
print(StudMarks.totalCount)  // 获取类型属性

stud1Mark2.InternalMarks = 87
print(StudMarks.totalCount)  // 获取类型属性

19 方法

在oc中,类是唯一能定义方法的类型,但在swift中,可以在类/结构体/枚举上定义方法

19.1 实例方法

  • 实例方法可以访问和修改实例属性,提供与实例目的相关的功能
  • 实例方法能够隐式访问它所属类型的所有的其他实例属性和方法
  • 实例方法只能被它所属的类型的某个特定实例调用,不能脱离实例而被调用
import Cocoa
class Counter {
  var count = 0
  func increment() { count += 1 }
  func incrementBy(amount: Int) { count += amount }
  func reset() { count = 0 }
}
let counter = Counter()
counter.increment()
print(counter.count)  // 1
counter.incrementBy(amount: 5)
print(counter.count)  // 6
counter.reset()
print(counter.count)  // 0

19.2 方法的局部参数名称和外部参数名称

swift默认给方法的第一个参数名称一个局部参数名称,默认给第二个和后续的参数名称为外部参数名称

import Cocoa

class division {
  var count: Int = 0
  func incrementBy(no1: Int, no2: Int) {  // no1为局部参数名称,no2为外部参数名称
    count = no1 / no2
    print(count)
  }
}
let counter = division()
counter.incrementBy(no1: 1800, no2: 3)  // 600

19.3 self属性

每个实例都有self属性,self完全等同于实例本身

import Cocoa
class Cal {
  let a: Int
  let b: Int
  let res: Int
  init(a: Int, b: Int) {
    self.a = a
    self.b = b
    self.res = a + b
  }
}
let sum = Cal(a: 1, b: 2)
print(sum.res)  // 3

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

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

相关文章

从方法论到最佳实践,深度解析企业云原生 DevSecOps 体系构建

作者&#xff1a;匡大虎 引言 安全一直是企业上云关注的核心问题。随着云原生对云计算基础设施和企业应用架构的重定义&#xff0c;传统的企业安全防护架构已经不能够满足新时期下的安全防护要求。为此企业安全人员需要针对云原生时代的安全挑战重新进行系统性的威胁分析并构…

5G_射频测试_测试模式解读(三)

Downlink test models FR1 test model 1.1 (NR-FR1-TM1.1)&#xff08;满PRB&#xff0c;QPSK&#xff09;FR1 test model 1.2 (NR-FR1-TM1.2)( QPSK/boosted/40% QPSK)FR1 test model 2 (NR-FR1-TM2)(64QAM 只有1个PRB 功率最低)FR1 test model 2a (NR-FR1-TM2a) )(256QAM 只…

Eureka使用详解

介绍主要特点主要功能与常用服务注册中心的比较Eureka与Zookeeper的区别和联系Eureka与Nacos的区别与联系Eureka与Consul的区别与联系 安装部署Eureka与CAP理论Eureka实现实时上下线Eureka常用注解Eureka架构模式 介绍 Eureka是一个基于REST的服务&#xff0c;主要用于AWS云中…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-帖子详情页实现

锋哥原创的SpringbootLayui python222网站实战&#xff1a; python222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火…

Element-UI 多个el-upload组件自定义上传,不用上传url,并且携带自定义传参(文件序号)

1. 需求&#xff1a; 有多个&#xff08;不确定具体数量&#xff09;的upload组件&#xff0c;每个都需要单独上传获取文件&#xff08;JS File类型&#xff09;&#xff0c;不需要action上传到指定url&#xff0c;自定义上传动作和http操作。而且因为不确定组件数量&#xff0…

SpringMVC-.xml的配置

文章目录 一、对pom.xml的配置二、对web.xml1.第一种方式2. 第二种方式 三、对SpringMVC.xml的配置 一、对pom.xml的配置 <!-- 打包成war包--><packaging>war</packaging> <dependencies><!-- SpringMVC--><dependency><gro…

Shiro框架:Shiro用户访问控制鉴权流程-Aop注解方式源码解析

目录 1.Spring Aop嵌入点解析 2.Shiro框架Aop切面逻辑解析 2.1 通过注解实现切点 2.2 通过增强逻辑执行校验过程 2.2.1 增强实现类AopAllianceAnnotationsAuthorizingMethodInterceptor 2.2.1.1 类图解析 2.2.1.2 实现增强方法 2.2.1.3 Shiro校验逻辑实现 2.2.1.3.1 …

代码随想录27期|Python|Day33|贪心算法|1005.K次取反后最大化的数组和|134. 加油站|135. 分发糖果

1005. K 次取反后最大化的数组和 思路比较简单&#xff0c;把所有的负数绝对值大的全部取反之后再在新的数组里把绝对值最小的重复取反即可。 class Solution(object):def largestSumAfterKNegations(self, nums, k):""":type nums: List[int]:type k: int:rt…

VS里那些实用的调试(debug)技巧

前言——————希望现在在努力的各位都能感动以后享受成功的自己&#xff01; 首先我们要来了解什么是bug——————bug本意是“昆虫”或“虫子”&#xff0c;现在⼀般是指在电脑系统或程序中&#xff0c;隐藏着的⼀些未被发现的缺陷或 问题&#xff0c;简称程序漏洞。 “…

Java导出Excel并合并单元格

需求&#xff1a;需要在导出excel时合并指定的单元格 ruoyi excel 项目基于若伊框架二次开发&#xff0c;本着能用现成的就不自己写的原则&#xff0c;先是尝试了Excel注解中needMerge属性 /*** 是否需要纵向合并单元格,应对需求:含有list集合单元格)*/public boolean needMer…

11 - PXC集群|MySQL存储引擎

PXC集群&#xff5c;MySQL存储引擎 数据库系列文章PXC集群配置集群测试集群 MySQL存储引擎存储引擎介绍mysql服务体系结构mysql服务的工作过程处理查询访问的工作过程处理存储insert访问的工作过程 什么是搜索引擎 存储引擎管理查看存储引擎修改存储引擎 存储引擎特点myisam存储…

20240119-子数组最小值之和

题目要求 给定一个整数数组 arr&#xff0c;求 min(b) 的总和&#xff0c;其中 b 的范围涵盖 arr 的每个&#xff08;连续&#xff09;子数组。由于答案可能很大&#xff0c;因此返回答案模数 Example 1: Input: arr [3,1,2,4] Output: 17 Explanation: Subarrays are [3]…

【排序算法】五、冒泡排序(C/C++)

「前言」文章内容是排序算法之冒泡排序的讲解。&#xff08;所有文章已经分类好&#xff0c;放心食用&#xff09; 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 冒泡排序1.1 原理1.2 代码实现&#xff08;C/C&#xff09;1.3 特性总结 冒泡排序 1.1…

基于Springboot的民宿在线预定平台(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的民宿在线预定平台(有报告)。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring…

SAI实例研究

实现目标 接到特定任务后&#xff0c;召唤生物攻击当前角色 例子 creature.id 15402&#xff08;即 smart_script.entryorguid&#xff09;共分为0和1两个事件阶段 第0阶段&#xff1a;第1条(id 0&#xff09;&#xff0c;第2条(id 1&#xff09;&#xff0c;第3条(id 2…

基于YOLOv8的目标识别、计数、电子围栏的项目开发过程

0 前言 用于生产环境中物体检测、识别、跟踪&#xff0c;人、车流量统计&#xff0c;越界安全识别 1 YOLOv8概述 YOLOv8 是Ultralytics的YOLO的最新版本。作为一种前沿、最先进(SOTA)的模型&#xff0c;YOLOv8在之前版本的成功基础上引入了新功能和改进&#xff0c;以提高性…

构建STM32MP133的Buildroot环境

意法半导体ST在坚持用 Yocto构建他们的OpenSTLinux MP1系列MCU&#xff0c;编译费劲&#xff0c;而且我们的应用不需要Yocto的环境&#xff0c;所以基于Buildroot的最小Linux系统更适合我们。 STM32MP133微处理器基于单Arm Cortex-A7内核&#xff0c;运行频率可达1 GHz&#x…

PACS医学影像采集传输与存储管理、影像诊断查询与报告管理系统,MPR多平面重建

按照国际标准IHE规范&#xff0c;以高性能服务器、网络及存储设备构成硬件支持平台&#xff0c;以大型关系型数据库作为数据和图像的存储管理工具&#xff0c;以医疗影像的采集、传输、存储和诊断为核心&#xff0c;集影像采集传输与存储管理、影像诊断查询与报告管理、综合信息…

使用JFLASH实现文件程序自动化合并及下载功能

主要总结下使用 SEGGER 工具集的 JFLASH 软件实现hex/bin文件合并以及程序的自动下载使用方法。 起因是最近使用到LVGL字库文件的制作&#xff0c;每次都要将分散的bin文件按既定分配的偏移作合并处理&#xff0c;刚开始使用的是二进制文件合并工具,文件少的时候还行&#xff…

C#使用DateTime.Now静态属性动态获得系统当前日期和时间

目录 一、实例 1.源码 2.生成效果 二、相关知识点 1.Thread类 &#xff08;1&#xff09;Thread.Sleep()方法 &#xff08;2&#xff09;Thread(ThreadStart) &#xff08;3&#xff09;IsBackground &#xff08;4&#xff09;Invoke( &#xff09; 2.CreateGrap…