Swift 不同凡响的地方

Swift 不同凡响的地方

switch(元组)

  • 特色swift

    • 其余语言中的switch语句只能比较离散的整形数据(字符能够转换成整数)
    • 可是swift中能够比较整数、浮点数、字符、字符串、和元组数据类型,并且它能够是离散的也可使连续的范围
    • 并且在swift中case语句不须要显示的添加break语句,分支语句会自动进行跳转
    • 每一个switch语句至少有一个default语句
  • switch中比较元组数组

    • 能够在元组中进行值绑定,来对某一个值进行判断
    • 可使用where 语句对元组中的条件进行判断

跳转语句

  • break、contune、fallthrough、return

break

  • 主要用户循环体中终止循环闭包

  • break的使用有两种方式框架

    break	// 	没有标签
    break label // 添加标签
    // break语句中标签的使用
    label1: for var x = 0; x < 5; x++ { // 标签1
        label2: for var y = 0; y > 0; y-- { // 标签2
            if x == y {
            break label1 // 默认是跳出标签2,加上标签,能够直接跳出到指定循环
            }
            print("(x,y) = (\(x),\(y))")
        }
    }

continue

  • continue 的使用和break相似,可使用标签指定继续的循环ide

    // continue语句中标签的使用
    label1: for var x = 0; x < 5; x++ { // 标签1
        label2: for var y = 0; y > 0; y-- { // 标签2
            if x == y {
                continue label1 // 默认是跳出标签2,加上标签,能够直接跳出到指定循环
            }
            print("(x,y) = (\(x),\(y))")
        }
    }

fallthrough

  • fallthrough是贯通语句,在swift的swiftch语句中case语句不能贯通,可是若是咱们须要设置贯通语句,可使用fallthrough语句
  • 在switch语句中case后fallthrough,会执行下一个case语句

函数

  • 参数传递函数

    • 外部参数名和内部参数名
    • 外部参数名能够在调用函数时显示出来
    func rectangle(W width:Int, H height:Int) -> Int {
    	// 	其中W\H是外部参数名,在外部调用这个方法时会显示出来,提示这个参数是神马意思
    	// width\height 是内部参数,在函数内部调用使用
    	return width * height
    }
    • 也可让内部便令名变为外部变量名,使用字符 “#”
    func rectangle(#width:Int, #height:Int) -> Int{
    	// 	其中W\H是外部参数名,在外部调用这个方法时会显示出来,提示这个参数是神马意思
    	// width\height 是内部参数,在函数内部调用使用
    	return width * height
    }
  • 参数默认值设计

    func rectangle(#width:Int = 100, #height:Int = 100) -> Int {
    	// 	其中W\H是外部参数名,在外部调用这个方法时会显示出来,提示这个参数是神马意思
    	// width\height 是内部参数,在函数内部调用使用
    	return width * height
    }
  • 可变参数代理

    func sum(numbers: Double... ) -> Double {
    	var total: Double = 0
    	for num in numbers {
    		total += num
    	}
    	return total
    }
  • 参数的引用传递rest

    • 在众多数据类型中,只有类是引用传递,其余的数据类型如整形、浮点型、布尔型、字符串、元组、集合、数据、枚举、结构体都是值传递。
    • 若是必定要把一个值传递的类型的数据变为引用传递模型的话,可以使用关键字'inout'
    func rectangle(inout width:Int, increased:Int = 1 ) {
    	width += increased
    }
    var value:Int = 10
    rectangle(&value) // 结果是11
    rectangle(&value,100) // 结果是111
  • 函数返回值code

    • 特别之处是能够返回一个元组,表示多个值
    func rectangleArea(width:Double, increased:Double = 1 ) -> (area:Double,height:Double) //返回面积和高度
  • 函数类型

    • 函数类型包括函数参数类型和返回值类型
    • (Double, Double) -> Double //传入宽高,计算面积
    • 这个就是函数类型,函数类型能够做为其余函数的返回类型
    • 好比写一个通用的方法来计算更多种图形的面积,这时可使用这个函数类型做为返回值
    • 函数类型还能够做为参数类型使用,能够直接使用返回值做为参数,而后能够在函数内部调用这个函数
  • 函数重载

    • 和C++中函数重载相似,可是在swift中函数返回值类型外部参数名 也能够做为不一样函数的判断标准
  • 嵌套函数

    • 能够在函数内部定义并调用函数

泛型和泛型函数

  • 泛型就是在运行时才肯定类型的一种机制,这个C++中的泛型一模一样

  • 就是定义一个模板,使用多种场景

  • 函数参数或者返回值到运行时才能肯定

    func add(a:Int, b:Int) -> Int
    	{
    		return a + b
    	}
    	func add(a:Double, b:Double) -> Double
    	{
    		return a + b
    	}
  • 若是用泛型计算两个数的和,能够写成下面这个样

    func add<T>)(a:T, b:T) -> T {
    		return a + b
    	}
    	// 或者指定多重类型
    	func add<T,U>(a:T, b:U) -> T {
    		return a + T(b)
    	}
  • 若是比较两个类型的话,那么必需要遵照Comparable协议才能够

    func isEquals<T: Comparable>(a:T, b:T) -> Bool {
    		return (a == b)
    	}

闭包

  • 闭包是自包含的匿名函数代码块,能够做为表达式、函数参数和函数返回值。

    { (参数列表) -> 返回值类型 in
    		语句组
    }

使用举例

  • 完整版本

    {(a:Int, b:Int) -> Int in 
    		return a + b
    	}
  • 简化版本 {a,b in return a + b }

    • 若是闭包中只有一条return语句,那么return 语句能够省略 {a,b in a + b }
    • 缩写参数名称 {$0 + $1} swift会自动推到出参数类型,$0表示第一个参数,$1表示第二个参数
    • 闭包做为返回值,直接能够为变量和常量赋值
    let reslut:Int = {(a:Int, b:Int) -> Int in 
    		return a + b
    	}(10, 89)
  • 捕获上下文中的变量和常量

    • 嵌套函数和闭包能够访问其所在上下文中的常量和变量,这就是捕获值。即使是定义这些常量或变量的做用域已经不存在,嵌套函数或闭包仍然能够在函数体内或闭包内修改或引用这些值。

swift中的面向对象

枚举

  • swift中枚举能够存储多种数据类型,并非真正的整数

    // 默认并非整形
    	enum WeekDays {		
    		case Monday
    		case Tuesday
    		case Wednesday
    		case Thursday
    		case Friday
    	}
    	// 简写
    		enum WeekDays {
    		case Monday, Tuesday, Wednesday, Thursday, Friday
    	}
  • 注意:在switch中使用枚举类型时,语句中的case必须所有包含枚举中全部成员,不能多也不能少,包括default语句。

  • 指定没枚举的原始值,能够是字符、字符串、整数、浮点数等

    // 指定枚举的原始值
    	enum WeekDays: Int {
    		case Monday = 0
    		case Tuesday
    		case Wednesday
    		case Thursday
    		case Friday
    	}
  • 原始值使用的话,要用到函数 toRaw()fromRaw()

结构体

  • swift中结构体和类很是相似,能够定义成员变量和方法
  • 结构体不具有继承、运行时强制类型转换、析构函数、引用计数等
  • 除了对象是引用传递,其余数据类型都是值传递,引用之间的比较可使用 ‘=’ 和 ‘!=’

可选类型和可选链

  • “?” 和 "!"

    • 不肯定一个变量是否有值,能够加 ?
  • 可选绑定 : 若是赋值不为nil的话就执行if语句

    if let result: Double? = divide(100,0) {
    	print("success")
    }
    else {
    	print("failure")
    }
  • 强制拆封 : 使用 ! 来强制拆封

    let result: Double? = divide(100,0)
    	print(result!)
  • 可选链

    • 一些可选类型内部包含其余可选类型,而后产生层级关系。

访问限定

  • 访问范围的界定主要有:模块和源文件
  • 访问级别:public、internal、private
  • 可修饰类、结构体、枚举等面向对象的类型,还能够修饰变量、常量、下标、元组、函数、属性等。以上这些统称“实体”
  • 使用方式
    • public : 只要在import进所在模块,那么在该模块中均可访问
    • internal : 只能访问本身模块的任何internal实体,不能访问其余模块中的internal实体,默认就是internal修饰符
    • private : 只能在当前源文件中访问的实体。
  • 设计原则
    • 若是是本身在本文件内部使用,就用默认的就行。
    • 若是是开发第三方框架的话,那么必定要设计好访问级别,接口必定要public。其余的能够private

属性和下标

一、存储属性

  • 存储属性适用于类和结构体两种类型,包括常量属性(let)和变量属性(var

    • 在一个类中定义一个结构体对象属性或者类对象属性时就算是存储属性,能够指定默认值
  • 能够对存储属性进行延迟加载

  • 属性观察者

    • 使用在通常的存储属性和计算属性上
    • willSet 在设置新值以前调用
    • didSet 在设置新值以后立刻调用
    var fullName: String {
        didSet {
             fullName = firstName + "." + secondName
        }

二、计算属性

  • 计算属性自己不存储数据,只从其余存储属性中得到数据。类、结构体、枚举均可以定义计算属性

  • 计算属性只能使用var修饰

    var firstName: String = "Jone"
    var secondName: String = "Hu"
    // 计算属性
    var fullName: String {
        get {
            return firstName + "." + secondName
        }
        set (newValue) {
            let names = newValue.componentsSeparatedByString(".")
            firstName = names[0]
            secondName = names[1]
        }
    }
  • 只读计算属性,只写set方法便可,这是能够省略set,直接return便可

    var firstName: String = "Jone"
    var secondName: String = "Hu"
    // 计算属性
    var fullName: String {
       return firstName + "." + secondName
    }

三、静态属性

  • 能够在类、结构体、枚举中定义静态属性

四、下标

  • 一些集合类型,可使用下标访问

    /**
    *  定义二维数组,使用下标访问数组
    *  内部仍是一个一维数组,不过展现给外界的时一个二维访问方式
    */
    struct DoubleArray {
        // 属性定义
        let rows: Int
        let cols: Int
        var grid: [Int]
        
        // 构造方法
        init(rows: Int, cols: Int) {
            self.rows = rows
            self.cols = cols
            grid = Array(count: rows * cols, repeatedValue: 0) // 利用泛型建立一个数组
        }
        
        // 下标定义
        subscript(row: Int, col: Int) -> Int {
            get {
                return grid[row * col + col]
            }
            set (newValue) {
                grid[row * col + col] = newValue
            }
        }
    }
    
    // 使用二维数组
    var arr2 = DoubleArray(rows: 10, cols: 10)
    
    // 初始化二维数组
    for var i = 0; i < 10; i++ {
        for var j = 0; j < 10; j++ {
            arr2[i,j] = i * j
        }
    }
    
    // 输出二维数组
    for var i = 0; i < 10; i++ {
        for var j = 0; j < 10; j++ {
            print("\t \(arr2[i,j])")
        }
        print("\n")
    }

方法

  • 类、结构体、枚举中均可以定义方法
  • 这里主要说结构体和枚举中方法的定义
    • 默认状况下,结构体和枚举中的方法是不能修改属性的
    • 若是要修改属性的话,须要在方法以前加关键字 mutating ,称之为变异方法

静态方法

  • 结构体和枚举中静态方法用static,类中静态方法使用class

  • 一、结构体中的静态方法

    • 不能访问示例属性和示例方法
    /**
    *  结构体中的静态方法
    */
    struct Account {
        var owner: String = "Jack"
        static var interestRate: Double = 0.668
        // 静态方法
        static func interestRateBy(amount: Double) -> Double  {
            return interestRate * amount
        }
        func messageWith(amount: Double) -> String {
            let interest  = Account.interestRateBy(amount)
            return "\(self.owner) 的利息是 \(interest)"
        }
    }
    // 调用静态方法
    print(Account.interestRateBy(10_000.00))
    //
    var myAccount = Account()
    print(myAccount.messageWith(10_000))
  • 二、枚举中的静态方法

    • 不能访问示例属性和示例方法
    /// 枚举中的静态方法
    enum Account1 {
        case 中国银行
        case 中国工商银行
        case 中国建设银行
        case 中国农业因银行
        static var interestRate: Double = 0.669
        // 静态方法定义
        static func interestBy(amount: Double) -> Double {
            return interestRate * amount
        }
    }
    // 静态方法的调用
    print(Account1.interestBy(10_000.00))
  • 三、类中的静态方法

    • 不能访问示例属性和示例方法
    /// 类中的静态方法,使用关键字class
    class Account2 {
        var ower: String = "Jack"
        class func interestBy(amount: Double) -> Double {
            return 0.889 * amount
        }
    }
    // 调用静态方法
    print(Account2.interestBy(10_000.00))

构造和析构

  • 只有类和结构体才有构造init()和析构函数deinit
  • 在建立实例过程当中须要一些初始化操做,这个过程称为构造
  • 在实例最后被释放的过程当中,须要清楚资源,这个过程称为析构
  • 注意: 构造器 能够重载,没有返回值

构造器

  • 构造器主作一些属性的初始化操做
  • 若是不写init方法,那么会自动生成一个空的init构造器
  • 若是有继承关系,要先调用父类的构造器
  • 横向代理与向上代理
    • 横向代理:构造器调用发生在本类内部,添加convenience关键字便可做为便利构造器,便利构造器必须调用本类内部的其余构造器
    • 向上代理:有继承关系,就先调用父类的构造器

析构器

  • 析构器只做用于类
  • 析构器没有返回值,没有参数,不能重载

继承

  • swift单继承
  • 重写属性、下标以及方法
  • 重写父类的方法使用override
  • 终止属性或者方法的继承可使用 final
  • 类型检查 is as Any AnyObject
    • is 类型判断
    • as 类型转换
    • Any 任何类型,包括类和其余数据类型
    • AnyObject 任何类

扩展和协议

扩展extension

  • 扩展的类型可使类、结构体、枚举
  • 扩展能够增长属性和方法
  • 扩展计算属性、方法、构造器、下标
  • 注意:扩展类的构造器的时只能增长遍历构造器,指定构造器和析构器只能由源类型指定

协议 protocol

  • 相似C++中的纯虚类
  • 能够定义属性和方法
  • 协议能够继承协议

swift内存管理

  • swift内存管理遵循ARC特性
  • 对引用类型进行引用计数,基本数据类型由系统管理

循环引用问题

  • swift中解决循环引用由两种方式
    • 一、弱引用(weak reference
    • 二、无主引用(unowned reference)
  • 弱引用能够没有值,所以必须设置成可选类型
  • 无主引用适用于引用对象永远有值

闭包中的循环引用问题

  • 闭包中的循环引用的解决方法和上面的同样,使用弱引用和无主引用

    class Person {
        let firstName: String = "Jack"
        let secondName: String = "lu"
        /**
        *  解决闭包强循环引用
        */
        lazy var fullName: (String, String) -> String = {
            // [weak self] (firstName: String, secondName: String) -> String in
            [unowned self] (firstName: String, secondName: String) -> String in
            return firstName + secondName
        }
    }

OC与Swift

  • OC和swift能够混合开发

  • 一、swift 调用 OC

    • 桥接文件 "<工程名>-Bridging-Header.h"
    • 在桥接文件中引入OC头文件便可
  • 二、OC调用swift

    • 包含头文件,这个头文件命名样式 "<工程名>-swift.h"
    • 在swift源文件中要把类声明为 @objc
    • 这时新建swift类就不须要选择新建swift文件,而是选择Cocoa Touch Class,而后选择语言类型位swift