Swift基础知识(二)
来源:互联网 发布:伊朗 沙特 知乎 编辑:程序博客网 时间:2024/06/05 11:56
闭包(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.单表达式闭包隐式返回因为闭包体只有一行代码,可以省略returnprint(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中闭包的最简单形式是嵌套函数。 // 函数的嵌套是一种特殊形式的闭包 函数类型作为返回值 sum可以保留上次的结果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 { // class definition goes here}struct SomeStructure { // structure definition goes here} 类名和结构体名的命名规范:大驼峰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") // 输出 "cinema is now 2048 pixels wide" print("hd is still \(hd.width ) pixels wide") // 输出 "hd is still 1920 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)") // 输出 "The frameRate property of theEighty is now 30.0"6.恒等运算符如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符: • 等价于 ( === ) • 不等价于 ( !== )类中的方法1.实例方法和类方法2.实例方法的调用3.self 属性// 实例方法的使用class Dog { var name: String = "" var age: Int = 0 // 创建实例方法 func run() { print("running") } // 传参 func wang(name: String) { // 在实力方法中调用属性时 必须使用self点语法调用 不然报错 // 此时的self为当前类对象 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) { // 在结构体中的实例方法 不能直接操作外面的属性 若想操作需加关键字mutating self.name = name } // 创建可变方法 mutating func run(){ // 在可变方法中 可以修改self的值 self = Cat(name: "金钱豹", age: 5) } // 类方法 static func jump() { print("jumping") }}属性 — 存储属性和计算属性1.存储属性一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。// 类中的存储属性class People { // 声明存储属性 var name: String = "" // let声明的属性 在外界无法通过点语法调用修改值 let age: Int = 0}// 这里let可以 因为指向的地址let people = People()people.name = "山治"// 不允许改变常量的值//people.age = 30//print(people.age)print(people.name)// 结构体里面的存储属性struct Tiger { var name: String = "" // 在结构体中 通过let声明的属性 不能通过点语法调用修改值 let age: Int = 0}// 值引用let ti = Tiger()// 若结构体对象// ti.name = "wang"//ti.age = 30延迟存储属性// 延迟存储属性class Monkey { var arr = [Int]() // 直到调用该属性时 才会进行属性的运算 类似于懒加载 lazy var name: String = ""}var mo = Monkey()mo.arr.append(1)mo.arr.append(2)// 当调用name时 CPU才会对name属性进行运算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() // 计算型属性 需要通过set/get方法的装实现 var center: Point { // centerPoint 等号右边的值 可用newValue代替 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 = 0rect.point.y = 0rect.size.width = 10rect.size.height = 20print(rect.center)只读计算属性只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。// 声明只读的属性class School { // 学校名称 var name: String = "" // 班级个数 var classNumber = 0 // 每个班级人的个数 var gradeNumber = 0 // 查看学校总人数 (只读属性) // 语法 声明变量 变量名:类型{return } var totalStudents: Int { return classNumber * gradeNumber }}var sc = School()sc.name = "qhfz"sc.classNumber = 20sc.gradeNumber = 10//sc.totalStudents = 90print("\(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 = 50print(Hotel.age)继承定义一个基类子类生成子类可以继续继承子类重写方法防止重写// 继承 当用final修饰类时 代表该类不能被继承class Car { var name = "" var size = 0 func run() { print("running^") } // 防止重写 final 防止子类对父类中方法的重写 final func stop() { print("stop") }}// 继承父类Carclass Bus: Car { var number = 0}// 没有多继承 但是可以多层继承var bus = Bus()// 继承的属性bus.name = "Bus"bus.size = 100// 继承的方法bus.run()// 派生的属性bus.number = 81// 多层继承可以继承基类中的属性和方法// 继承自Busclass RedBus: Bus { var color = "red" // 重写父类的方法 override 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() {// self.name = "cat"// print("在构造方法中给属性赋值")// } // 带有参数的构造函数// init(a: String){// self.name = a// // } // 带有外部参数的构造函数// init(name param1: String, age param2: Int){// self.name = param1// self.age = param2// } // 隐藏所有外部参数// init(_ param1: String, _ param2: Int) {// self.name = param1// self.age = param2// } // 在构造函数中可以访问没有被初始化的常量属性 init(n: Int) { self.num = n }}//var animal = Animal()//var animal = Animal(a: "dog")//var animal = Animal(name: "monkey", age: 5)//var animal = Animal("chicken",2)var animal = Animal(n: 100) print(animal.num)默认构造器结构体的逐一成员构造器// 默认的构造器class Mouse { var name = ""}// 每个类中会有默认构造器 init(){} 不写这行代码 也会联想小括号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") } // 析构函数 -- 最后调用的方法 当ARC销毁对象是调用析构函数 deinit { print("deinit") }}var desk: Desk? = Desk(name: "Teacher Li Desk")//打印结果: 重写构造函数 千万不要忘记super.init Teacher Li Deskprint(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 类名:父类,协议,协议2.。。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方法的封装 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 get方法的封装 set{ arr[a] = newValue } get { return arr[a] } }}let person = Person()person[0] = 200print(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//if a is Int {// print("Int")//}// Any 任何类型var objInt: Any = aif objInt is Int { print("Int")}class A { var name = ""}class B: A {}class C {}var b = B()// 判断对象是否属于类或者父类// AnyObject 与id一致 可以指向任何实例,一般指向对象 Any是执行任何类型var objB: AnyObject = bif objB is A { print("B")}as! as? 类型转换// as! as? 类型转换// 类类型做数据转换 objB as! B 将objB该类型转换成B类型var obj = objB as! B// 用as?做强制转换 如果强制转换成功 则是转换的数据类型 如果转换失败,则是nilvar obj2 = objB as? Cif obj2 == nil { print("不能转化为该类型")}异常处理// 异常处理// 声明异常enum MyError: ErrorType { case Error0 case OutOfRange case ErrorOther}func divide(a: Int, b: Int) throws -> Int { if b == 0 { // 抛出异常 : 1.首先将函数定义成throws 函数 throw MyError.Error0 } else { return a / b }}// 调用函数// 抛出异常就必须接收异常do { let rs = try divide(10, b: 0) print(rs)} catch MyError.Error0 { print("除数不能为0")}// 通过try! try? 调用throwing函数 // try? 有异常为nil 没异常为值//let rs = try? divide(5, b: 0)//if rs != nil {// print(rs!)//} else {// print("youyichang-")//}// try! 在确定throwing函数肯定无异常时 可以通过try!调用
0 0
- Swift基础知识(二)
- Swift基础知识(二)
- Swift基础知识补充(二)
- Swift中的基础知识总结(二)
- swift基础知识
- Swift 基础知识
- Swift基础知识
- Swift基础知识
- swift 基础知识
- Swift 基础知识
- Swift基础知识
- Swift基础知识
- swift 基础知识
- swift的基础知识
- Swift基础知识_01
- swift基础知识<一>
- Swift 入门 基础知识
- Swift 基础知识Part2
- java 获得当前时间前指定几个小时的时间
- 第十五周OJ——按长度截断
- js使用post 方式打开新窗口
- Hive函数编程-数学运算
- Handler源码窥探。
- Swift基础知识(二)
- 一步一步学习数据结构(3)-链表及其操作实战
- Error:duplicate files during packaging of APK
- 当Spring遇见MongoDB,五分钟搞定CRUD
- codeforces 735 B.Urbanization (简单题)
- Logistic回归
- UITableView那些事
- 架构师到底是做什么的?
- 线程安全的单例模式