swift基础语法

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

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

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

相关文章

Git学习笔记(第7章):IDEA实现Git操作(VSCode)

目录 7.1 配置忽略文件 7.2 初始化本地库 7.3 添加暂存区、提交本地库 7.4 修改文件 补充&#xff1a;工具栏简介 7.1 配置忽略文件 问题引入 在版本控制系统中&#xff0c;有些文件或目录是不需要纳入版本管理的&#xff0c;比如编译产生的临时文件、日志文件、缓存文件等…

基于springboot+vue的网上购物商城(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

hugo的常规使用操作

hugo的常规使用操作&#xff08;不断完善中&#xff09; 找到theme主题中config.toml 一般都会通过theme中复制到自己项目的config.toml中做修改和补充&#xff0c;来完善不同的业务需求 Hugo静态资源载入逻辑 原理 将图片信息放到static中&#xff0c;但是在文章中写的时…

电脑存储位置不够怎么办

电脑内存不够怎么办&#xff01;&#xff01;&#xff01; 我前段时间经常因为电脑D盘内存不够而苦恼&#xff08;毕竟电脑内存就那么丁点&#xff0c;C盘作为系统盘不能随便下东西的情况下&#xff0c;就只能选择其他盘进 方法一&#xff1a;检查电脑硬盘的分区情况&#xf…

Unity下实现跨平台的RTMP推流|轻量级RTSP服务|RTMP播放|RTSP播放低延迟解决方案

2018年&#xff0c;我们开始在原生RTSP|RTMP直播播放器的基础上&#xff0c;对接了Unity环境下的低延迟播放&#xff0c;毫秒级延迟&#xff0c;发布后&#xff0c;就得到了业内一致的认可。然后我们覆盖了Windows、Android、iOS、Linux的RTMP推送、轻量级RTSP服务和RTSP|RTMP播…

《WebKit 技术内幕》学习之五(3): HTML解释器和DOM 模型

3 DOM的事件机制 基于 WebKit 的浏览器事件处理过程&#xff1a;首先检测事件发生处的元素有无监听者&#xff0c;如果网页的相关节点注册了事件的监听者则浏览器会将事件派发给 WebKit 内核来处理。另外浏览器可能也需要处理这样的事件&#xff08;浏览器对于有些事件必须响应…

BGP Local-preferenct 、AS-Path、 Origin 综合选路实验

Local-preference&#xff1a; 本地优先级&#xff0c;公认任意&#xff0c;仅能在 AS 内使用&#xff08;IBGP内传递&#xff09;&#xff0c;不能在EBGP传递&#xff0c;默认值 100&#xff0c;越大越优。用于离开本 AS &#xff0c;在 IBGP 的入、出方向都可使用&#xff0c…

双端Diff算法

双端Diff算法 双端Diff算法指的是&#xff0c;在新旧两组子节点的四个端点之间分别进行比较&#xff0c;并试图找到可复用的节点。相比简单Diff算法&#xff0c;双端Diff算法的优势在于&#xff0c;对于同样的更新场景&#xff0c;执行的DOM移动操作次数更少。 简单 Diff 算法…

光学期刊1

光学领域的你&#xff0c;如何评价最近发布的光学期刊分区&#xff1f; 如题&#xff0c;附分区表 20240122 知乎 同样先写结论&#xff1a;时代变了&#xff0c;发国产没错的。参考light当年开局多艰难&#xff0c;被各种diss口碑差&#xff0c;很多投一区守门员不中的也…

二进制部署高可用k8s集群V1.20.11版本

文章目录 一、操作系统初始化配置&#xff08;所有节点均执行&#xff09;1、关闭防火墙2、关闭selinux3、关闭swap4、根据规划修改主机名5、在master节点上添加host6、将桥接的IPv4流量传递到iptables的链7、时间同步 二、部署Etcd集群1、准备cfssl证书生成工具2、生成Etcd证书…

2024年软件测试面试题大全【含答案】

Part1 1、你的测试职业发展是什么&#xff1f;【文末有面试文档免费领取】 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做…

tableau mysql 驱动安装

最便捷&#xff0c;最快速的方式。 整体流程&#xff1a;首先得知道你电脑mysql的版本&#xff0c;然后去官网下载ODBC驱动。 mysql版本&#xff1a;浏览器搜一些。 高版本驱动应该是兼容低版本的。 ODBC驱动&#xff1a; 选择第一个&#xff0c;下载&#xff0c;直接msi安装…

学习笔记之 机器学习之预测雾霾

文章目录 Encoder-DecoderSeq2Seq (序列到序列&#xff09; Encoder-Decoder 基础的Encoder-Decoder是存在很多弊端的&#xff0c;最大的问题就是信息丢失。Encoder将输入编码为固定大小的向量的过程实际上是一个“信息有损的压缩过程”&#xff0c;如果信息量越大&#xff0c;…

POKT Network (POKT) :进军百亿美元市场规模的人工智能推理市场

POKT Network&#xff08;又称 Pocket Network&#xff09;是一个去中心化的物理基础设施网络&#xff08;DePIN&#xff09;&#xff0c;它能够协调并激励对任何开放数据源的访问&#xff0c;最初专注于向应用程序和服务提供商提供区块链数据。 自 2020 年主网上线以来&#x…

MSG3D

论文在stgcn与sta-lstm基础上做的。下面讲一下里面的方法&#xff1a; 1.准备工作 符号。这里是对符号进行解释。 一个人体骨骼图被记为G(v,E) 图卷积&#xff1a; 图卷积定义 考虑一种常用于处理图像的标准卷积神经网络 (CNN)。输入是像素网格。每个像素都有一个数据值向…

大数据开发之电商数仓(hadoop、flume、hive、hdfs、zookeeper、kafka)

第 1 章&#xff1a;数据仓库 1.1 数据仓库概述 1.1.1 数据仓库概念 1、数据仓库概念&#xff1a; 为企业制定决策&#xff0c;提供数据支持的集合。通过对数据仓库中数据的分析&#xff0c;可以帮助企业&#xff0c;改进业务流程、控制成本&#xff0c;提高产品质量。 数据…

网络:FTP

1. FTP 文件传输协议&#xff0c;FTP是用来传输文件的协议。使用FTP实现远程文件传输的同时&#xff0c;还可以保证数据传输的可靠性和高效性。 2. 特点 明文传输。 作用&#xff1a;可以从服务器上下载文件&#xff0c;或将本地文件上传到服务器。 3. FTP原理 FTP有控制层面…

Java技术栈 —— JVM虚拟机

JVM虚拟机 一、字节码(Byte-Code)1.1 如何查看字节码&#xff1f;1.2 如何理解字节码的作用&#xff1f; 二、JVM内存模型&#xff08;极其重点&#xff0c;必须牢牢把握住&#xff09;2.1 方法区2.2 虚拟机栈2.3 本地方法栈2.4 堆2.5 程序计数器2.6 面试必问 三、GC机制四、JV…

【华为 ICT HCIA eNSP 习题汇总】——题目集7

1、一台 PC 的 MAC 地址是 5489-98FB-65D8 &#xff0c;管理员希望该 PC 从 DHCP 服务器获得指定的 IP 地址为192.168.1.11/24&#xff0c;以下命令配置正确的是&#xff08;&#xff09;。 A、dhcp static-bind ip-address 192.168.1.11 24 mac- address 5489-98FB-65D8 B、dh…

力扣740. 删除并获得点数

动态规划 思路&#xff1a; 选择元素 x&#xff0c;获得其点数&#xff0c;删除 x 1 和 x - 1&#xff0c;则其他的 x 的点数也会被获得&#xff1b;可以将数组转换成一个有序 map&#xff0c;key 为 x&#xff0c; value 为对应所有 x 的和&#xff1b;则问题转换成了不能同…