• swift语言学习总结


    1. Var 表示变量, let表示常量。
    2. 数组和map, 都用中括号[].可以直接赋值。可以用下标或键访问。

    var shoppingList = ["catfish", "water", "tulips", "blue paint”]//最后一个可以加逗号。

    shoppingList[1] = "bottle of water"

    var occupations = [

        "Malcolm": "Captain",

        "Kaylee": "Mechanic",

    ]

    空数组就赋[], 而空map 就赋[:]。有点无语。

    1. 字符串处理。用\() 可以处理字符串的变量插入。

    let apples = 3

    let oranges = 5

    let appleSummary = "I have \(apples) apples."

    let fruitSummary = "I have \(apples + oranges) pieces of fruit."

    三个双引号(""")来包含多行字符串内容

    4.swift也有可空类型, String?, 同样用!表示非空。但是不像其他语言用null表示空, 而是nil。非要别出新裁。

    双??的用法和dart一样。

    1. Switch语法,支持任何类型的case。而且不需要用break, 找到case后执行完自己会退出switch,不会往下执行。当需要提前退出时,也可以用break。多个case可以用逗号合并。还有:区别匹配case 100..<1000;元组匹配(1,1)。  Case let Where语句。fallthrough可以继续下一个case。
    2. 条件语句和循环语句都允许不用包含在括号里面, if, for-in, while,repeat-while。
    3. repeat-while就是do-while
    4. 在for循环中,..< 来表示下标范围, 但不包含上界, 如果包含的就用…

    var total = 0

    for i in 0..<4 {// 0到3

        total += i

    }

    for i in 0..<4 {// 0到4

        total += i

    }

    1. 强制类型转换是用转换后的类型加上括号。Int(3.14)转换后就是3.
    2. 可以定义类名的别名,typealias。   typealias AudioSample = Int   AudioSample就可以当Int来使用了。这种傻逼功能还是少用。让人想起c/c++宏定义魔窟。
    3. 元组。 (name:type, name:type),和kotlin的很像。let http200Status = (statusCode: 200, description: "OK”)。针对函数返回值很有用的。

    1. 可选绑定 if let的用法。 把一个可控类型的参数赋值给一个正常参数,如果可控参数有值,就赋值成功,同时if语句是true, 在if语句里面就不需要用!来表示非空了。还可以多个一起,只要一个不成功就是false。

    if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {

    }

    1. 运算符方面,包含了java的所有功能, 包括三元运算符是一样的,这点很好比kotlin强。另外,增加了??和单双边运算符[…]
    2. 字符串方面和java大同小异。 字符串插值\(), 去语义#”  ”#. 字符串拼接也是+,和java一样。
    3. 数组方面。 数组类型定义是这样:[type],由于有类型推断,也可以不用写。 支持两个数组相加后合并到一起。

    15.数组修改,追加append, 删除remove, 追加另外一个数组+=, 插入insert, 判空isEmpty。按照方法来说,应该是链表实现的。

    16.集合set,方法和java差不多。

    1. Guard关键词,和 if let相识,只是在不满足时会跟一个else。
    2. 关于函数,总体和kotlin一样。但返回是用->表示;在函数参数前可以加标签注释, 如果参数名前加了下划线_j就不能加了;动态参数用…. ;当函数体只有一条代码,返回时,可以不带return;函数类型的使用也和kotlin类似。
    3. 闭包整体和kotlin的一样。闭包是引用类型。

    reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )

    尾随方式

    reversedNames = names.sorted(){ (s1, s2) -> Bool in return s1 > s2 }

    可以用$0,$1…,来特指参数。 如果其中一个不用,那用_替代。

    reversedNames = names.sorted(){ return $0>$1 }

    可以把括号也省掉

    reversedNames = names.sorted{ return $0>$1 }

    如果闭包在最后,那么也可以是尾随闭包。

        func test1( values:String, process:()->Bool){

        }

            test1(values:""){true}

    闭包逃逸,就是说闭包传到函数里面,但是没有执行闭包, 只是把闭包引用给了别人。要加一个 @escaping

    var completionHandlers: [() -> Void] = []

    func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {

        completionHandlers.append(completionHandler)

    }

    自动闭包就是函数定义。

    let customerProvider = { customersInLine.remove(at: 0) } //定义了一个函数;

    在函数中直接写执行代码没有括号。要加 @autoclosure

    func serve(customer customerProvider: @autoclosure () -> String) {

        print("Now serving \(customerProvider())!")

    }

    serve(customer: customersInLine.remove(at: 0))

    可以即是自动闭包又可以是逃役闭包,

    var customerProviders: [() -> String] = []

    func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {

        customerProviders.append(customerProvider)

    }

    1. 枚举,成员前要加case。

    两种定义方式:

    enum CompassPoint {

        case north

        case south

        case east

        case west

    }

    enum Planet {

        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune

    }

    var directionToHead = CompassPoint.west

    一旦 directionToHead 被声明或者被推断出为 CompassPoint 类型,可以间断成这样:

    directionToHead = .east

    遍历枚举成员:

    enum Beverage: CaseIterable {

        case coffee, tea, juice

    }

    let numberOfChoices = Beverage.allCases.count

    枚举关联值,这个功能很好,就是附带信息用的。和kotlin的sealed class有点像,就是没有执行方法。比如把异常的code和error情况塞到里面。

    enum Barcode {

        case upc(Int, Int, Int, Int)

        case qrCode(String)

    }

    var productBarcode = Barcode.upc(8, 85909, 51226, 3)

    使用时如下:

    switch productBarcode {

    case .upc(let numberSystem, let manufacturer, let product, let check):

        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")

    case .qrCode(let productCode):

        print("QR code: \(productCode).")

    }

    枚举初始值。枚举值可以是任何类型的值,可以是int/double/String。

    和C#一样,会递增。如果不设值第一个默认是0

    enum Planet: Int {

        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune

    }

    enum CompassPoint: String {

        case north, south, east, west

    }

    let earthsOrder = Planet.earth.rawValue

    // earthsOrder 值为 3

    let sunsetDirection = CompassPoint.west.rawValue

    // sunsetDirection 值为 "west"

    前面提到“枚举值可以是任何类型的值”。所以也可以是枚举自身啊。所以这里就有递归问题了。

    而且递归是支持的,用关键字:indirect

    enum ArithmeticExpression {

        case number(Int)

        indirect case addition(ArithmeticExpression, ArithmeticExpression)

        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)

    }

    你也可以在枚举类型开头加上 indirect 关键字来表明它的所有成员都是可递归的:

    indirect enum ArithmeticExpression {

        case number(Int)

        case addition(ArithmeticExpression, ArithmeticExpression)

        case multiplication(ArithmeticExpression, ArithmeticExpression)

    }

    例子:let five = ArithmeticExpression.number(5)

    let four = ArithmeticExpression.number(4)

    let sum = ArithmeticExpression.addition(five, four)

    let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

    因为枚举的最终使用还是在选择语句上:

    func evaluate(_ expression: ArithmeticExpression) -> Int {

        switch expression {

        case let .number(value):

            return value

        case let .addition(left, right):

            return evaluate(left) + evaluate(right)

        case let .multiplication(left, right):

            return evaluate(left) * evaluate(right)

        }

    }

    1. 结构体struct。 swift还保留着struct。可能是内存回收机制缺陷导致的,便于一些情况下的回收。还有就是速度更快一点,相当于是在栈上。

    struct是值类型,所以赋值的时候是值拷贝,生成了另外一个struct实例。和类差异并不大。

    和类相同的地方:

    • 定义属性用于存储值
    • 定义方法用于提供功能
    • 定义下标操作用于通过下标语法访问它们的值
    • 定义构造器用于设置初始值
    • 通过扩展以增加默认实现之外的功能
    • 遵循协议以提供某种标准功能

    类还有如下的附加功能:

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

    类的恒等运算符

    • 相同(===)
    • 不相同(!==)

    使用这两个运算符检测两个常量或者变量是否引用了同一个实例:

    if tenEighty === alsoTenEighty {

        print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")

    }

    1. 属性。 分为存储属性和计算属性。 存储属性就是property,计算属性就是getter/setter方法。

    变量用var,常量用let.

    懒加载,用 lazy 来标示一个延时加载存储属性。必须声明成var, 因为是构造后才使用, 不能是let。

    但是swift的懒加载不支持多线程安全。

    class DataImporter {

        /*

        DataImporter 是一个负责将外部文件中的数据导入的类。

        这个类的初始化会消耗不少时间。

        */

        var fileName = "data.txt"

        // 这里会提供数据导入功能

    }

    class DataManager {

        lazy var importer = DataImporter()

        var data = [String]()

        // 这里会提供数据管理功能

    }

    计算属性getter/setter, 下面是完整的方式:

    struct Point {

        var x = 0.0, y = 0.0

    }

    struct Size {

        var width = 0.0, height = 0.0

    }

    struct Rect {

        var origin = Point()

        var size = Size()

        var center: Point {

            get {

                let centerX = origin.x + (size.width / 2)

                let centerY = origin.y + (size.height / 2)

                return Point(x: centerX, y: centerY)

            }

            set(newCenter) {

                origin.x = newCenter.x - (size.width / 2)

                origin.y = newCenter.y - (size.height / 2)

            }

        }

    }

    简化Get, 当单行代码时。可以省去return。

    简化Set, 用newValue替代设置值。

    struct CompactRect {

        var origin = Point()

        var size = Size()

        var center: Point {

            get {

                Point(x: origin.x + (size.width / 2),

                      y: origin.y + (size.height / 2))

            }

            set {

                origin.x = newValue.x - (size.width / 2)

                origin.y = newValue.y - (size.height / 2)

            }

        }

    }

    当只有getter时,可以简化, 省去get关键字和{}。

    struct Cuboid {

        var width = 0.0, height = 0.0, depth = 0.0

        var volume: Double {

            return width * height * depth

        }

    }

    属性观察器

    • willSet 在新的值被设置之前调用
    • didSet 在新的值被设置之后调用

    即使新值和当前值相同的时候也不例外。

    在父类初始化方法调用之后,在子类构造器中给父类的属性赋值时,会调用父类属性的 willSet 和 didSet 观察器。而在父类初始化方法调用之前,给子类的属性赋值时不会调用子类属性的观察器。

    class StepCounter {

        var totalSteps: Int = 0 {

            willSet(newTotalSteps) {

                print("将 totalSteps 的值设置为 \(newTotalSteps)")

            }

            didSet {

                if totalSteps > oldValue  {

                    print("增加了 \(totalSteps - oldValue) 步")

                }

            }

        }

    }

    属性包装器,就是getter/setter的套用模版。可以是结构体也可以是类。

    @propertyWrapper

    struct SmallNumber {

        private var maximum: Int

        private var number: Int

        var wrappedValue: Int {

            get { return number }

            set { number = min(newValue, maximum) }

        }

        init() {

            maximum = 12

            number = 0

        }

        init(wrappedValue: Int) {

            maximum = 12

            number = min(wrappedValue, maximum)

        }

        init(wrappedValue: Int, maximum: Int) {

            self.maximum = maximum

            number = min(wrappedValue, maximum)

        }

    }

    struct NarrowRectangle {

        @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int

        @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int

    }

    这样height最大值就是5,width最大值就是4。

    1. 结构体/类的下标,枚举也可以。定义下标使用 subscript 关键字。

    一维数组

    subscript(index: Int) -> Int {

        get {

          // 返回一个适当的 Int 类型的值

        }

        set(newValue) {

          // 执行适当的赋值操作

        }

    }

    二维数组:

    subscript(row: Int, column: Int) -> Int {

        get {

          // 返回一个适当的 Int 类型的值

        }

        set(newValue) {

          // 执行适当的赋值操作

        }

    }

    1. 继承。 用:继承, 用self替代this, 调用超类方法用super。重写在func前加override。防止重写用final。
    2. 构造函数。全是用init()来替代类名构造, 要么已经初始化好了,直接class()。可选属性在init里可以不初始化。

    常量的初始化,可延迟到构造函数里。

  • 相关阅读:
    5分钟学会canvas的使用
    C++ Day3
    LeetCode 309 周赛
    Python - Flask 实现自动登录
    【智能家居项目】FreeRTOS版本——将裸机程序改造成FreeRTOS程序 | DHT11温湿度传感器
    taobao.trade.get( 获取单笔交易的部分信息),淘宝店铺订单接口,淘宝oAuth2.0接口,淘宝R2接口代码对接分享
    串口控制小车和小车PWM调速
    韦东山 嵌入式Linux驱动开发基础知识 【hello驱动 像单片机那样驱动 用结构体封装驱动
    自动化办公|办公软件和亿图脑图MindMaster快捷键
    Windows10安装麒麟桌面V10双系统
  • 原文地址:https://blog.csdn.net/zjuter/article/details/138161556