闭包(Closures)
* 闭包是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
* 在Swift中的闭包与C、OC中的blocks和其它编程语言(如Python)中的lambdas类似。
* 闭包可以捕获和存储上下文中定义的的任何常量和变量的引用。这就是所谓的变量和变量的自封闭,
* 因此命名为”闭包“("Closures)").Swift还会处理所有捕获的引用的内存管理。
闭包的形式有:
* (1)全局函数都是闭包,有名字但不能捕获任何值。
* (2)嵌套函数都是闭包,且有名字,也能捕获封闭函数内的值。
* (3)闭包表达式都是无名闭包,使用轻量级语法,可以根据上下文环境捕获值。
* (4) 全局函数和嵌套函数其实就是特殊的闭包
Swift中的闭包有很多优化的地方:
* (1)根据上下文推断参数和返回值类型
* (2)从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)
* (3)可以使用简化参数名,如$0, $1(从0开始,表示第i个参数...)
* (4)提供了尾随闭包语法(Trailing closure syntax)
以sort 方法为例 讲解闭包的
sort(@noescape isOrderedBefore: (Self.Generator.Element, Self.Generator.Element) -> Bool) -> [Self.Generator.Element]
1.在sort方法中调用函数
let arr = ["a", "b", "c", "m", "e", "d"]
func sortString(a: String, b: String) -> Bool {
return a < b
}
print(arr.sort(sortString))
2.使用闭包形式
完整闭包写法是在花括号内有参数列表和返回值,用关键字in表明闭包体的开始
闭包的语法:
{(参数)-> 返回值类型 in 功能代码}
let arr1 = ["a", "e", "q", "b"]
print(arr1.sort({ (a: String, b: String) -> Bool in
return a > b
}))
简化闭包
1.根据上下文推断类型
参数列表都没有指明类型,也没有指明返回值类型,这是因为swift可以根据上下文推测出
print(arr1.sort({ a, b in
return a < b
}))
2.单表达式闭包隐式返回
因为闭包体只有一行代码,可以省略return
print(arr1.sort({ a, b in
a > b
}))
3.参数名称缩写(($i,i=0,1,2...从0开始的)Swift会推断出闭包需要两个参数)
print(arr1.sort({$0 > $1}))
4.运算符函数
print(arr1.sort(>))
5.尾随闭包
* 尾随闭包(Trailing Closures)
* 如果函数需要一个闭包参数作为参数,且这个参数是最后一个参数,而这个闭包表达式又很长时,
* 使用尾随闭包是很有用的。尾随闭包可以放在函数参数列表外,也就是括号外。如果函数只有一个参数,
* 那么可以把括号()省略掉,后面直接跟着闭包。
func tailClosure(a: Int, b: (Int, Int) -> Int){
print("\(a) \(b(1,2))")
}
tailClosure(10) { (a: Int, b: Int) -> Int in
return a + b
}
6.捕获值 - 函数嵌套
* 闭包可以根据环境上下文捕获到定义的常量和变量。闭包可以引用和修改这些捕获到的常量和变量,
* 就算在原来的范围内定义为常量或者变量已经不再存在(很牛逼)。
* 在Swift中闭包的最简单形式是嵌套函数。
func increametMaker(cnt: Int) -> () -> Int {
var sum = 0
func increamet() -> Int {
sum += cnt
return sum
}
return increamet
}
let maker = increametMaker(10)
print(maker())
7.闭包是引用类型
let maker1 = maker
print(maker1())
类和结构体
1.类和结构体的对比
Swift 中类和结构体有很多共同点。共同处在于:
• 定义属性用于储存值
• 定义方法用于提供功能
• 定义下标用于通过下标语法访问值
• 定义初始化器用于生成初始化值
• 通过扩展以增加默认实现的功能
• 符合协议以对某类提供标准功能
与结构体相比,类还有如下的附加功能:
• 继承允许一个类继承另一个类的特征
• 类型转换允许在运行时检查和解释一个类实例的类型
• 取消初始化器允许一个类实例释放任何其所被分配的资源
• 引用计数允许对一个类的多次引用
2.类和结构体的语法定义
通过关键字class和struct来分别表示类和结构体,并在一对大括号中定义它们的具体内容
class SomeClass {
}
struct SomeStructure {
}
类名和结构体名的命名规范:大驼峰
3.类和结构体实例化
结构体和类都可以使用初始化器语法来生成新的实例。初始化器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如Resolution()或VideoMode()。但是结构体还有另外一个初始化方式:成员逐一初始化器
var p = Person()
var s = Student(name: "xiaowang", age: 30)
4.属性访问 —— 以点语法的形式访问属性
5.结构体和枚举是值类型 类是引用类型
值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝。
引用类型在被赋予到一个变量,常量或者被传递到一个函数时,操作的并不是其拷贝。因此,引用的是已存在的实例本身而不是其拷贝。
枚举
enum ASCIIControlCharacter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
值类型
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
print("cinema is now \(cinema.width) pixels wide")
print("hd is still \(hd.width ) pixels wide")
引用类型
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
6.恒等运算符
如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符:
• 等价于 ( === )
• 不等价于 ( !== )
类中的方法
1.实例方法和类方法
2.实例方法的调用
3.self 属性
class Dog {
var name: String = ""
var age: Int = 0
func run() {
print("running")
}
func wang(name: String) {
self.name = name
}
static func jump() {
print("jumping")
}
}
结构体中的方法
1.值类型实例方法中修改属性
2.在可变方法中给 self 赋值
struct Cat {
var name: String = ""
var age: Int = 0
func voice() {
print("喵~")
}
mutating func eat(name: String) {
self.name = name
}
mutating func run(){
self = Cat(name: "金钱豹", age: 5)
}
static func jump() {
print("jumping")
}
}
属性 — 存储属性和计算属性
1.存储属性
一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。
class People {
var name: String = ""
let age: Int = 0
}
let people = People()
people.name = "山治"
print(people.name)
struct Tiger {
var name: String = ""
let age: Int = 0
}
let ti = Tiger()
延迟存储属性
class Monkey {
var arr = [Int]()
lazy var name: String = ""
}
var mo = Monkey()
mo.arr.append(1)
mo.arr.append(2)
mo.name = "孙悟空"
print(mo.name)
2.计算属性
计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
便捷 setter 声明 — 如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称newValue
struct Point {
var x = 0
var y = 0
}
struct Size {
var width = 0
var height = 0
}
class Rect {
var point = Point()
var size = Size()
装实现
var center: Point {
set {
point.x = newValue.x - size.width / 2
point.y = newValue.y - size.height / 2
}
get {
let centerX = point.x + size.width / 2
let centerY = point.y + size.height / 2
return Point(x: centerX, y: centerY)
}
}
}
var rect = Rect()
rect.point.x = 0
rect.point.y = 0
rect.size.width = 10
rect.size.height = 20
print(rect.center)
只读计算属性
只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
class School {
var name: String = ""
var classNumber = 0
var gradeNumber = 0
var totalStudents: Int {
return classNumber * gradeNumber
}
}
var sc = School()
sc.name = "qhfz"
sc.classNumber = 20
sc.gradeNumber = 10
print("\(sc.name)学校共有\(sc.totalStudents)学生")
类属性语法 与 属性监视器
class Hotel {
var name = "7tian" {
willSet {
print(name)
}
didSet {
print(name)
}
}
static var age: Int = 10
}
var hotel = Hotel()
hotel.name = "hanting"
Hotel.age = 50
print(Hotel.age)
继承
定义一个基类
子类生成
子类可以继续继承子类
重写方法
防止重写
class Car {
var name = ""
var size = 0
func run() {
print("running^")
}
final func stop() {
print("stop")
}
}
class Bus: Car {
var number = 0
}
var bus = Bus()
bus.name = "Bus"
bus.size = 100
bus.run()
bus.number = 81
class RedBus: Bus {
var color = "red"
override func run() {
super.run()
print("RedBus-Running^^")
}
}
var redBus = RedBus()
redBus.name = "RedBus"
redBus.run()
构造和析构
构造函数
不带外部名的构造器参数
构造函数参数的内部名称和外部名称
构造过程中常量属性的修改
class Animal {
func run() {
print("running^^^^^")
}
var name = ""
var age = 0
let num: Int
init(n: Int) {
self.num = n
}
}
var animal = Animal(n: 100)
print(animal.num)
默认构造器
结构体的逐一成员构造器
class Mouse {
var name = ""
}
var mouse = Mouse()
struct Phone {
var name = ""
var age = 0
}
var phone = Phone(name: "iPhone", age: 4)
构造器的继承和重写
析构过程
class Table {
var name = ""
init(name: String){
self.name = name
}
}
class Desk: Table {
override init(name: String) {
super.init(name: name)
print("重写构造函数 千万不要忘记super.init")
}
deinit {
print("deinit")
}
}
var desk: Desk? = Desk(name: "Teacher Li Desk")
print(desk!.name)
desk = nil
只读属性类型的拓展
方法扩展
extension Int {
var a: Int {
return self * self
}
}
print(5.a)
class Duck {
var name = ""
}
extension Duck {
var age: String{
return self.name + "qianfeng"
}
func run() {
print("Dusk Running")
}
}
var duck = Duck()
duck.run()
duck.name = "唐老鸭"
print(duck.age)
协议语法
协议中属性的用法
协议中方法的用法
委托模式
protocol Work: class {
func teaching()
}
@objc protocol Teach {
optional
func say()
}
class Worker: Work, Teach {
func teaching() {
print("协议中的方法")
}
@objc func say() {
print("可选的协议方法")
}
}
下标的使用
var arr = [2,3,1,7]
print(arr[2])
class Days {
var days = ["Mon", "Tues", "wend", "Thir", "Fri"]
subscript (a: Int) -> String {
get {
return days[a]
}
}
}
let days = Days()
let day = days[0]
print(day)
class Person {
var arr = Array(count: 10, repeatedValue: 0)
subscript (a: Int) -> Int {
set{
arr[a] = newValue
}
get {
return arr[a]
}
}
}
let person = Person()
person[0] = 200
print(person[0])
可选链
class Eye {
var num = 2
}
class Student {
var eye: Eye? = Eye()
}
let st = Student()
print(st.eye!.num)
is类型检测 Any与AnyObject
var a = 20
var objInt: Any = a
if objInt is Int {
print("Int")
}
class A {
var name = ""
}
class B: A {
}
class C {
}
var b = B()
var objB: AnyObject = b
if objB is A {
print("B")
}
as! as? 类型转换
var obj = objB as! B
var obj2 = objB as? C
if obj2 == nil {
print("不能转化为该类型")
}
异常处理
enum MyError: ErrorType {
case Error0
case OutOfRange
case ErrorOther
}
func divide(a: Int, b: Int) throws -> Int {
if b == 0 {
throw MyError.Error0
} else {
return a / b
}
}
do {
let rs = try divide(10, b: 0)
print(rs)
} catch MyError.Error0 {
print("除数不能为0")
}