参考教程
https://www.runoob.com/swift/swift-data-types.html
swift代码规范
https://juejin.cn/post/7129465308376465422
必须要有苹果电脑且安装Xcode
Swift是类型安全的语言,编译时会进行类型检查
import Cocoa
var mySting = "Hello, World!"
print(myString)
可以使用import语句引入任何的Objective-C(C语言的严格超集)
// 这是单行注释(单行注释以//开头)
/* 多行注释
多行注释(以/*开始,以*/结束,可以嵌套单行注释)*/
Swift不要求每行结尾使用分号,但在同一行书写多条语句必须用分号隔开
import Cocoa
var myString = "Hello, World!"; print(myString)
标识符是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字
Swift使用Unicode编码,可以使用中文,甚至聊天表情符
import Cocoa
// 如果一定要使用关键字作标识符,可以在关键字前后加`
let `class` = "Runoob"
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 // 这样写是可以的
为避免错误,尽量严格缩进
import Cocoa
print("Runoob") // 使用print函数输出,如果多个print,默认换行输出
// 如果不想换行则将terminator设置为空字符串,这样每个输出以空格分隔
for x in 0...10 { // 这是循环语句,后续会介绍
print("\(x)", terminator: "") // \()可以将x变为字符串
}
// 如果接收用户的输入使用readLine()
let theInput = readLine()
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
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)
// 使用typealias关键字定义
import Cocoa
typealias Feet = Int // 定义类型别名
var distance: Feet = 100
print(distance)
如果没有显示的制定类型,Swift会根据初始值进行类型推断
import Cocoa
let meaningOfLife = 42 // meaningOfLife被推断为Int类型
let pi = 3.1415 // pi被推断为Double类型,而非Float类型
let anotherPi = 3 + 0.1415 // anotherPi被推断为Double类型
使用var关键字来声明
import Cocoa
// 方式一:
var varA: Int
varA = 42
// 方式二:
var varB: Double = 3.14
import Cocoa
var 你好 = “你好”
print(你好)
import Cocoa
var age: Int = 24
print("My age is \(age)")
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("你的字符串没有值")
}
常量类似于变量,区别在于常量的值一旦设定就不能改变,而变量的值可以随意更改,使用let关键字来声明
import Cocoa
let constA = 42
print(constA)
import Cocoa
let constB: Double = 3.14
print(constB)
和变量的命名规则相同,同4.2
和变量的输出方式相同,同4.3
二进制前缀为0b,八进制前缀为0o,十六进制前缀为0x,十进制没有前缀
let decimalInteger = 17 // 十进制17
let binaryInteger = 0b100001 // 二进制17
let octalInteger = 0o21 // 八进制17
let hexadecimal = 0x11 // 十六进制17
let decimalDouble = 12.1e2 // 十进制浮点型字面量:12.1*10^2
let hexadecimalDouble = 0xC.3p3 // 十六进制浮点型字面量:12.3*2^3
字符串型字面量中不能包含未转义的引号,未转义的反斜线、回车符或换行符
+、-、*、/、%
Swift中已经取消了++和–
==、!=、>、<、>=、<=
对二进制位进行操作
>>
:按位右移,右移后右边的数位被丢弃,左边的空位用0填充=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
原则
如果创建一个数组,并赋值给一个变量,则创建的集合可添加、删除、修改,如果赋给常量则数组不可更改
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] // 必须用逗号隔开,不能只用空格隔开
// 通过索引获取数组值:索引下标从0开始
import Cocoa
var someInts = [Int](repeating: 10, count: 3)
var someVar: Int = someInts[0]
print(someVar)
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])
import Cocoa
// 使用for-in循环遍历数组
var someStrs: [String] = ["Hello", "World"]
for item in someStrs {
print(item)
}
// 可以使用+合并两种已存在的相同类型数组
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)
}
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)
import Cocoa
// 1. 创建一个空字典,键的类型为Int,值的类型为String
// 法一(推荐):
var someDict1: [Int: String] = [:]
// 法二:
var someDict2 = [Int: String]()
// 2. 创建字典实例:注意冒号前无空格,冒号后有空格
var someDict3: [Int: String] = [1: "one", 2: "two"]
import Cocoa
// 根据字典的键来访问值
var someDict: [Int: String] = [1: "one", 2: "two"]
var varA: String? = someDict[1] // 注意如果标注类型,必须是可选类型
var varB = someDict[2] // varB也是可选类型
print(varA!)
print(varB!)
// 使用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 新的值")
// 法一:使用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
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")
// 使用字典的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
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
// 形式
// func funcname(形参名: 形参类型) -> returnType {
// ...
// return ...
// }
import Cocoa
func cityHello(city: String, hello: String) -> String {
return city + " " + hello
}
print(cityHello(city: "北京", hello: "你好!")) // 注意city和hello不能省略
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: "你好", "北京")
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
元组作为返回值
// 定义一个函数,实现找到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)")
(Int, Int)?
,注意与(Int?, Int?)
不同,(Int, Int)?
整个元组是可选的,不只是元组中的每个元素值。上面找最小值和最大值的函数,如果传入的array为空,则应该返回nilimport 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: "你好")
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
函数嵌套指的是函数内定义一个新的函数,外部函数可以调用函数内定义的函数
定义:闭包是自包含的功能代码块,可以在代码中使用或者用来作为参数传值,和匿名函数类似
形式:
语法
{(parameters) -> return type in
statements
}
import Cocoa
let divide = {(val1: Int, val2: Int) -> Int in
return val1 / val2
}
print(divide(200, 20))
全局函数
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]
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
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
import Cocoa
enum DaysofWeek {
case Sunday
case Monday
case Tuesday
case Wednesday
case Thursday
case Friday
case Saturday
}
var weekDay = DaysofWeek.Thursday
weekDay = .Friday
相关值:可以是不同类型
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
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
应用场景
注意:结构体实例是通过值传递而不是引用
类可以定义属性和方法,和其他语言不同,swift不要求为自定义类去创建独立的接口和实现文件,只需要在一个单一文件中定义一个类,系统会自动生成面向其他代码的外部接口
import Cocoa
class MarkClass {
var mark: Int
init(mark: Int) { self.mark = mark }
}
let marks = MarkClass(mark : 100)
print("成绩为\(marks.mark)")
共同点:
与结构体相比,类还有如下的附加功能
类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例
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("引用不同的类实例") }
属性可分为存储属性和计算属性
存储属性是存储在特定类或结构体的实例里的一个常量或变量,可以在定义存储属性的时候指定默认值,也可以在构造过程中设置或修改存储属性的值
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
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性,必须将延迟存储属性声明为变量(var关键词),因为常量属性在构造完成之前必须要有初始值。延迟存储属性常用于延时对象的创建、属性的值依赖于其他未知类。
import Cocoa
class Sample {
lazy var no = Number() // lazy定义延迟存储属性,且该属性为var
}
class Number {
var name = "world"
}
var firstSample = Sample()
print(firstSample.no.name)
计算属性不直接存储值,而是提供一个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
只有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
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性添加属性观察器。不需要为无法重载的计算属性添加属性观察器,因为可以通过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
和实例属性区分开,类型属性是类型定义的一部分写在类型最外层的花括号里,使用关键字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) // 获取类型属性
在oc中,类是唯一能定义方法的类型,但在swift中,可以在类/结构体/枚举上定义方法
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
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
每个实例都有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