Swift 学习笔记

一、常量与变量

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)"
}

七、元组(Tuples)

        元组是一宗数据结构,类似于数组和字典,用于定义一组数据。

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)")

八、可选类型(Optional)

在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

Swift 学习笔记_第1张图片

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 }

调用

Swift 学习笔记_第2张图片

7、消除返回值未使用的警告信息,在函数前加@discardableResult

Swift 学习笔记_第3张图片

 

 十、闭包

闭包是一个特殊的函数

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

// 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)")
    }
}

十八、typealias 别名

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 }

十九、inline 内联函数

函数体比较长、包含递归调用或者包含动态派发的函数不会被自动内联

设置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、关联值举例

Swift 学习笔记_第4张图片

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))

二十一、
 

你可能感兴趣的:(Swift,swift,开发语言,ios)