1、使用let定义常量,定义之后不可修改
let num = 10
// 常量不可修改
num = 20 // × 报错
2、使用var定义变量,定义之后可以修改
var num = 10
// 变量可以修改
num = 20
!编译器会根据常量或变量的赋值来自动推断它的数据类型。
1、整型 Int
2、浮点型 Float
3、字符串 String
4、数组
5、对象类型
6、结构体
基本运算时必须保证类型一致,否则会报错。值不会隐式转换,需要显式转换成其他数据类型。
let a = 10
let b = 2.0
// 错误写法
// let c = a + b
// 必须先转换
let c = Double(a) + b
let d = a + Int(b)
1、拼接字符串
let str1 = "Hello"
let str2 = "Swift"
let str3 = str1 + " " + str2
2、遍历字符串
var str = "Hello Swift"
for chr in str {
print(chr)
}
3、插入字符串
let year = 5
let str = "Swift is \(year) years old!"
4、格式化字符串
let key = "CN"
let value = "中国"
let str = String(format:"%@=%@", key, value)
5、三引号表示多行字符串,引号所在行,引号后面不能有其他元素
let str = """
Hello Swift
Hello Swift
Hello Swift
"""
1、数组的声明
let array:Array
var array:[String]
2、初始化数组
// 定义可变数组必须初始化后才能使用
var array1 : [String] = [String]()
// 定义常数组
let array2 : [Any] = ["今年", 2021]
// 定义时直接初始化
var array3 = ["a", "b", "c"]
// 先定义再初始化
var array4 = Array
array = ["a", "b", "c"]
3、数组的操作
// 添加元素
array.append("a")
// 删除元素
array.removeFirst()
array.removeLast()
array.removeAt(1)
// 修改元素
array[0] = "abc"
// 获取元素值
array[0]
// 合并数组,相同类型才能合并
var array1 = ["a", "b", "c"]
var array2 = ["A", "B", "C"]
var array3 = array1 + array2
4、遍历数组
// 区间遍历
for i in 0..
5、带间隔的区间
// 从4开始,累加2,到10
for tick in stride(from: 4, through: 10, by: 2) {
print(tick)
}
// 4 6 8 10
字典由键和值两个集合组成,键集合不能有重复元素,值集合可以重复。键和值成对出现。
1、初始化字典
//常字典
let dict1 = ["name":"张三", "age":21]
//可变字典
var dict2 = [String:Any] = [String : Any]()
2、操作字典
// 添加数据
dict["height"] = 1.80
// 删除数据
dict.removeValueForKey("height")
// 修改数据
dict["name"] = "小明"
// 查询字典
dict["name"]
// 合并字典
var dict1 = ["name" : "张三", "age", 21]
var dict2 = ["height" : 1.80]
for (key, value) in dict2 {
dict1[key] = value
}
3、遍历字典
// 遍历所有值
for value in dict.values {
print(value)
}
// 遍历所有键
for key in dict.keys {
print(key)
}
// 遍历所有键值
for (key,value) in dict {
print("\(key):\(value)"
}
元组是一宗数据结构,类似于数组和字典,用于定义一组数据。
1、定义元组
("2021", "张三", 21, 1.80)
(id:1, name:"张三", age:21, height:1.80)
2、元组的使用
// 元组:http 404
// 写法一
let error = (404, "Not Found")
print("\(error.0) means \(error.1)")
// 写法二
let error = (code:404, info:"Not Found")
print("\(error.code) means \(error.info)")
// 写法三
let (errorCode, errorInfo) = (404, "Not Found")
print("\(errorCode) means \(errorInfo)")
在swift开发中,nil也是一个特殊的类型
1、可选类型的定义
// 定义可选类型
// 写法一
let str : Optional = nil
// 写法二
let str : String? = nil
// 错误写法
// let str : String = nil
2、可选类型的使用
// 定义
var str : String? = nil
// 赋值
str = "Hello Swift"
// 打印
print(str)
// Output : Optional("Hello Swift")
3、可选类型的解包
解包是指去除可选类型的真实值
var str : String? = nil
str = "Hello Swift"
print(str!)
// 如果可选类型为nil,强制取出其中的值,程序会崩溃
// str = nil
// print(str!)
// 正确写法
if str!=nil {
print(str!)
}
// 简单写法
if var str=string {
print(str)
}
4、可选类型使用例子
// 正确写法:使用可选类型接收
let url : URL? = URL(string:"http://www.baidu.com")
// 错误写法
// let url = URL = URL(string:"http://www.baidu.com")
// 通过url创建request对象
if let tempUrl = url {
let request = NSURLRequest(URL : tempUrl)
}
5、可选类型绑定,实现登录
// if 语句中的可选项绑定只能作用在大括号内
func login(_ info: [String: String]) {
let username: String
if let tmp = info["username"] {
username = tmp
} else {
print("请输入用户名")
return
}
let password: String
if let tmp = info["password"] {
password = tmp
} else {
print("请输入密码")
return
}
// 判断用户名密码
print("用户名:\(username),密码:\(password)")
}
login(["username": "Jack", "password": "123"])
login(["username": "Jack"])
login(["password": "123"])
// guard 语句中的可选项绑定可以用在外部作用域
func login(_ info: [String: String]) {
guard let username = info["username"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
// 判断用户名密码
print("用户名:\(username),密码:\(password)")
}
函数格式
func 函数名(参数列表)->返回值类型 {
代码
return 返回值
}
func是关键字,多个参数列表-之间可以用逗号","分隔,也可以没有参数
使用箭头"->"指向返回值类型
如果函数没有返回值,返回值为void部分可以省略
0、文档注释
/// 求和【概述】
///
/// 将两个数相加【更详细的的描述】
///
/// - Parameter v1: 第一个数
/// - Parameter v2: 第二个数
/// - Returns: 两个数的和
///
/// - Note:传入两个数即可【批注】
///
func sum(v1: Float, v2: Float) -> Float {
v1 + v2
}
sum(2.5, 3.0)
按住ALT点击函数就会出现函数说明,详见Swift.org - API Design Guidelines
1、常见函数类型
// 没有参数,没有返回值
func test() {
print("Hello Swift")
}
// 有参数,没有返回值
func test(name : String) {
print("Hello \(name)")
}
// 没参数,有返回值
func test()->String {
return "Hello Swift"
}
// 有参数,有返回值
func test(name : String) : String {
return "Hello \(name)"
}
// 返回元组
func cal(v1 : Int, v2 : Int) -> (sum: Int, diff: Int, avg: Int) {
let sum = v1 + v2
return (sum, v1-v2, sum>>1)
}
let result = cal(v1:10, v2:30)
result.sum // 40
result.diff // -20
result.avg //20
// 函数类型作为函数参数
func sum (a: Int ,b: Int) -> Int{ a + b}
func differece(a: Int ,b: Int) -> Int { a - b}
func printResult(_ mathFn:(Int ,Int) -> Int ,_ a: Int ,_ b: Int){
print(mathFn(a,b))
}
printResult(sum(a:b:), 30, 40) // 70
printResult(differece(a:b:), 60, 50) // 10
// 函数类型作为返回值 (返回值是函数类型的函数,叫做高阶函数)
func next(_ input: Int, _ none: String) -> Int {
input+1
}
func previous(_ input: Int, _ none: String) -> Int {
input-1
}
func forward(_ forward: Bool) -> (Int, String) -> Int {
forward ? next : previous
}
print(forward(false)(3, "")) // 2
print(forward(true)(3, "")) // 4
// 嵌套函数 (将函数定义在函数内部)
func forward(_ forward: Bool) -> (Int) -> Int {
func next(_ input: Int) -> Int { input + 1 }
func previous(_ input: Int) -> Int { input - 1 }
return forward ? next(_:) : previous(_:)
}
print(forward(false)(3)) // 2
print(forward(true)(3)) // 4
2、外部参数名和内部参数名
在函数外面可以看到的参数就是外部参数,在函数内部可以看到的参数就是内部参数。
// number1,number2是外部参数名,num1,num2是内部参数名
func test1(number1 num1 : Int, number2 num2 : Int)->Int {
return num1 + num2
}
// 不一致时,调用必须使用外部名称
var result = test2(number1 : 10, number2 : 20)
// 外部参数名和内部参数名相同
func test2(num1 : Int, num2 : Int)->Int {
return num1 + num2
}
var result = test2(num1:10, num2:20)
// 外部参数名的意义
func goToWork(at time: String) {
print("this time is \(time)")
}
// 使用外部参数名,使函数使用时读起来更通顺,如同 go to work at 8:00
goToWork(at: "08:00")
3、默认参数
func test(name :String="China")->String {
return "This is made from \(name)"
}
let r1 = test("US")
let r2 = test()
4、可变参数
swift中函数的参数个数可以变化,它就可以接受不确定数量的输入类型参数(相同类型)。
func test(numbers:Double...)->Double {
var total : Double = 0
for number in numbers {
total += number
}
return total
}
var result = test(10.0, 15, 20)
5、引用类型
默认情况下,函数的参数是值传递,如果想改变外面的变量,就需要传递变量的地址,关键字inout
func swap(a : inout Int, b : inout Int) {
let temp = a
a = b
b = temp
}
var a = 10
var b = 20
swap(a:&a, b:&b)
print("a:\(a),b:\(b)")
6、函数的重载
函数名称相同,但是参数不同
//原函数
func sum(a: Int , b: Int) -> Int{ a + b }
// 参数个数不同
func sum(a: Int ,b: Int ,c: Int) -> Int{ a + b + c }
//参数类型不同
func sum(a: Int ,b: Double) -> Double { Double(a) + b }
// 忽略标签
func sum(_ a: Int ,_ b: Int) -> Int{ a + b }
//参数标签不同
func sum (v1: Int ,v2: Int) -> Int{ v1 + v2 }
调用
7、消除返回值未使用的警告信息,在函数前加@discardableResult
闭包是一个特殊的函数
1、定义闭包
类型:(形参列表)->(返回值),定义闭包类型时,直接写()->(),再填充参数和返回值
{
(形参)->(返回值类型) in
// 执行代码
}
2、闭包的使用
// 定义网络请求类
class HttpTool : NSObject {
func loadRequest(callBack: ()->()) {
print("加载数据...")
callBack()
}
}
// 网络请求
let httpTool = HttpTool()
httpTool.loadRequest({()->() in
print("加载完成")
})
3、闭包的简写
如果闭包没有参数和返回值,in和in之前的内容可以省略
httpTool.loadRequest({
print("加载完成")
})
4、尾随闭包
尾随闭包的写法:
如果闭包是函数的最后一个参数,则可以将闭包写在()后面。、如果函数只有一个参数,并且这个参数是闭包,那么()也可以不写
httpTool.loadRequest() {
print("加载完成")
}
// 开发中建议这样写
httpTool.loadRequest {
print("加载完成")
}
5、闭包的循环使用
如果在HttpTool中有对闭包进行强引用,则会形成循环引用
class HttpTool: NSObject {
// 定义属性,强引用传入的闭包
var callBack: (()->())?
func loadRequest(callBack: ()->()) {
callBack()
self.callBack = callBack
}
}
// swift中解决循环应用的方式
// [weak self]()->() in
let httpTool = HttpTool()
httpTool.loadRequest {[weak self] in
self.view.backgroundColor = UIColor.redColor()
}
定义:用的时候才加载
// lazy的作用是只会赋值一次
lazy var array : [String] = {
()->[String] in
return ["a", "b", "c"]
}()
1、类的定义
class 类名 : SupoerClass {
// 定义属性和方法
}
2、类的属性
用于存储变量和常量
class Student : NSObject {
// 存储属性
var age : Int = 0
var name : String?
var score : Double = 0.0
}
// 创建学生对象
let stu = Student()
// 赋值
stu.age = 15
stu.name = "张三"
stu.score = 90.0
不存储实际值,而是提供一个getter和setter来间接获取和设置其他属性
存储属性一般只提供getter方法
如果只提供getter,而不提供setter,则该计算属性为只读属性,并且可以省略get()
class Student : NSObject {
// 存储属性
var age : Int = 0
var name : String?
var scoreChinese : Double = 0.0
var scoreEnglish : Double = 0.0
// 计算属性
var scoreAverage : Double {
get {
return (scoreChinese + scoreEnglish)/2
}
// newValue是系统分配的变量名,内部存储着新值
set {
self.scoreAverage = newValue
}
}
}
类属性与类相关联,而不是与类的实例相关联,类属性使用static来修饰
class Student : NSObject {
// 存储属性
var age : Int = 0
var name : String?
var scoreChinese : Double = 0.0
var scoreEnglish : Double = 0.0
// 计算属性
var scoreAverage : Double {
get {
return (scoreChinese + scoreEnglish)/2
}
// newValue是系统分配的变量名,内部存储着新值
set {
self.scoreAverage = newValue
}
}
// 类属性
static var classCount : Int = 0
}
// 设置类属性的值
Student.classCount = 2
3、监听属性的改变
Swift中可以通过属性观察者来监听和相应属性值的变化
通常是监听存储属性和类属性的改变,我们通过设置一下观察方法来定义观察者
willSet : 在属性值被存储之前设置。此时新属性值作为一个常量参数被传入。该参数名默认为newValue,我们可以自己定义该参数名
didSet : 在新属性值被存储后立即调用。与willSet相同,此时传入的是属性的旧值,默认参数名为oldValue
class Person : NSObject (
var name : String? {
// 可以给newValue自定义名称
willSet() {
//属性即将改变,还未改变时会调用该方法,newValue用来存储新值
print(newValue)
}
didSet() {
// 属性值已经改变了会调用的方法,oldValue用来存储旧值
print(oldValue)
}
}
var age : Int = 0
var height : Double = 0.0
}
let p = Person()
// 在赋值时,监听该属性的改变
p.name = "张三"
创建一个类时,必然会调用一个构造函数,如果是继承自NSObject,可以对父类的构造函数进行重写
1、构造函数的基本使用
class Person : NSObject (
var name : String = ""
var age : Int = 0
// 重写NSObject的构造方法
override init() {
name = ""
age = 0
}
let p = Person()
2、初始化时给属性赋值
我们在创建一个对象时就会给属性赋值,可以自定义构造函数,如果自定义了构造函数,会覆盖init()方法
class Person : NSObject (
var name : String?
var age : Int = 0
// 自定义构造函数
init(name : String, age : Int) {
self.name = name
self.age = age
}
}
let p = Person(name: "张三", age: 21)
1、if语句
let a = 10
if a>9 {
print(a)
}
2、if/else if/else语句
let a = 10
if a<9 {
print("lese than 9")
}
else if a>9 {
print("more than 9")
else {
print("It's 9")
}
3、三目运算符
var a = 10
var b = 20
var result = a>b?a:b
print(result)
4、guard语句
语法:当条件表达式为true时,跳过else语句中的内容,执行后面的代码;当条件表达式为false时,执行else语句中的内容,跳转语句一般是return、break、continue和throw
guard 条件表达式 else {
// do something...
return
}
// do something...
使用实例:
var age = 18
func online(age : Int) {
guard age>=18 else {
print("回家")
return
}
print("可以上网")
}
online(age)
5、switch分支
switch后面可以不跟(),case后面默认可以不跟break
let sex = 0
switch sex {
case 0 :
print("男")
case 1 :
print("女")
default :
print("未知")
}
case,default后面不能跟{},使用关键字fallthrough可以实现case穿透
let sex = 0
switch sex {
case 0 :
fallthrough
case 1 :
print("正常人")
default :
print("异常")
}
// 跟下面相同
switch sex {
case 0, 1 :
print("正常人")
default :
print("异常")
}
// 0,1 : 正常人
switch支持多种数据类型
// 浮点型
let f = 3.14
switch f {
case 3.14 :
print("π")
default :
print("not π")
}
// 字符串类型
let oprator = "+"
switch oprator {
case "+" :
print("plus")
case "-" :
print("minus")
case "*" :
print("*")
case "/" :
print("divide")
default :
break
}
// 区间判断
let score = 90
switch score {
case 0..<60:
print("不及格")
case 60..<80:
print("及格")
case 80..<90:
print("良好")
case 90..<100:
print("优秀")
default :
print("满分")
}
// 元组判断
let point = (1, 1)
switch point {
case (0, 0):
print("Point is zero")
case (_, 0):
print("Point is on axis X")
case (0, _):
print("Point is on axis Y")
case (-2...2, -2...2):
print("point is in the box")
default:
print("point is out of the box")
}
// 值绑定
let point = (2, 0)
switch point {
case (let x, 0):
print("on the axis-x of x value is \(x)")
case (0, let y):
print("on the axis-y of y value is \(y)")
case let (x, y):
print("x, y value is \(x), \(y)")
}
// where
let point = (1, -1)
switch point {
case let (x, y) where x == y :
print("on the line x == y")
case let (x, y) where x == -y :
print("on the line x == -y")
case let (x, y) :
print("x, y is \(x), \(y)")
}
// 将所有正数加起来
var numbers = [10,-10,20,-20,30,-30]
var sum = 0
for num in numbers where num>0 {
sum += num;
}
print(sum) // 60
1、for 循环
for i in 0..<10 {
print(i)
}
for i in 0...10 {
print(i)
}
2、while 循环
var a = 0
while a < 10 {
a += 1
}
3、repeat while 循环
var b = 0
repeat {
print(b)
b += 1
} while b<20
通过标签可以控制外部循环
outer: for i in 1...4 {
for k in 1...4 {
if k==3 {
continue outer
}
if i==3 {
break outer
}
print("i==\(i), k==\(k)")
}
}
1、 给类型起别名
typealias Byte = Int8
typealias Short = Int16
typealias Long = Int64
2、给元组起别名
typealias Date = (year: Int, month: Int, day: Int)
func test(_ date: Date) {
print("The date is \(date.year)-\(date.month)-\(date.day).")
}
test((2021, 1, 1))
3、给函数类型起别名
typealias IntFn = (Int, Int) -> Int
func diff(v1: Int, v2: Int) -> Int {
v1 - v2
}
let fn: IntFn = diff
fn(20, 10) // 10
//传参
func setFn(_ fn: IntFn) {}
setFn(diff)
// 返回
func getFn() -> IntFn { diff }
函数体比较长、包含递归调用或者包含动态派发的函数不会被自动内联
设置Optimize For Speed就会自动将某些函数变成内联函数
// 永远不会被内联
@inline(never) func test() {
print("test")
}
// 开启编译器优化后,即使代码很长,也会被内联(递归调用和动态派发函数除外)
@inline(__always) func test() {
print("test")
}
1、基本用法
// 两种写法完全等价
enum Direction {
case north
case south
case east
case west
}
enum Direction {
case north, south, east, west
}
// 调用
var dir = Direction.west
dir = Direction.east
dir = .north // 可以省略枚举类型
print(dir) // north
// 用在switch语句中
switch dir {
case .north:
print("n")
case .south:
print("s")
case .east:
print("e")
case .west:
print("w")
}
2、关联值
将枚举的成员值跟其他类型的关联存储在一起
// 成绩
enum Score {
case points(Int) // 具体分值
case grade(Character) // A,B,C...
}
var score = Score.points(96)
score = .grade("A")
switch score {
case let .points(i):
print(i, "points")
case let .grade(i):
print("grade", i)
} // grade A
// 年月日
enum Date {
case digit(year: Int, month: Int, day: Int) // 数字的年月日
case string(String) // 字符串的年月日
}
var date = Date.digit(year: 2021, month: 12, day: 26)
date = .string("2021-09-10")
switch date {
case .digit(let year, let month, let day):
// 与下句等价
// case let .digit(year, month, day):
// 可以写成
// case .digit(let year, var month, var day):
print(year, month, day, separator: "-")
case let .string(value):
print(value)
}
3、关联值举例
enum Password {
case number(Int, Int, Int, Int)
case gesture(String)
}
var password = Password.number(1, 3, 5, 7)
password = .gesture("12369")
switch password {
case let .number(n1, n2, n3, n4):
print("Password is number : ", n1, n2, n3, n4)
case let .gesture(str):
print("Password is gesture : ", str)
}
4、枚举的原始值(rawValue)
枚举成员可以使用相同类型的默认值预先关联,这个默认值叫原始值
enum PokerSuit: Character {
case spade = "♠"
case heart = "♥"
case diamond = "◇"
case club = "♣"
}
var suit = PokerSuit.spade
print(suit) // spade
print(suit.rowValue) // ♠
print(PokerSuit.club.rawValue) // ♣
enum Grade: String {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
var grade = Grade.perfect
print(grade) // perfect
print(grade.rawValue) // "A"
print(Grade.perfect.rawValue) // A
print(Grade.great.rawValue) // B
print(Grade.good.rawValue) // C
print(Grade.bad.rawValue) // D
如果枚举的原始值类型是Int、String,Swift会自动分配原始值,String分配为名称字符串,Int分配序号0,1,2,3,如果Int中有指定,那么下一个自动递增
enum Direction: String {
case north = "north"
case south = "south"
case east = "east"
case west = "west"
}
// 等价于
enum Direction: String {
case north, south, east, west
}
print(Direction.north) // north
print(Direction.north.rawValue) // north
5、枚举的递归
// 算术表达式
indirect enum ArithmeticExpression {
case number(Int)
case sum(ArithmeticExpression , ArithmeticExpression )
case diff(ArithmeticExpression , ArithmeticExpression )
}
// 等价于
enum ArithmeticExpression {
case number(Int)
indirect case sum(ArithmeticExpression , ArithmeticExpression )
indirect case diff(ArithmeticExpression , ArithmeticExpression )
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.sum(five, four)
let diff = ArithmeticExpression.diff(sum four)
func calculate(_ expr: ArithmeticExpression) -> Int {
switch expr {
case let .number(value):
return value
case let .sum(left, right):
return calculate(left) + calculate(right)
case let .diff(left, right):
return calculate(left) - calculate(right)
}
}
print(calculate(diff))
二十一、