【学习】重学Swift5-面相对象、协议编程
六、面向对象编程
-
常见高阶函数
// map print(numbers.map { $0 * 10}) // filter print(numbers.filter{ $0 > 4 }) // reduce print(numbers.reduce(10) { $0 + $1 }) // flatMap print(arrayNumber.flatMap{ $0.map { $0 * 10}}) // compactMap let names:[String?] = ["zhangsn", "lsi", nil, "wangwu", nil , "zhaoliu"] print(names.count) print(names.compactMap{$0}) print(names.compactMap{$0?.count}) print(names.count)
-
函数式编程
// 命令式编程风格常常迫使我们处于性能考虑,把不同的任务交织起来,以便能够一次循环来完成多个任务。 // 函数式编程用map()、filter()这些高阶函数把我们解放出来,让我们站在更高的抽象层次上去考虑问题,把问题看的更清楚。 // 简洁 // 面向对象编程通过封装不确定因素来使代码能被人理解;函数式编程通过尽量减少不确定因素来使代码被人理解 // 在面向对象的命令式编程语言中,重用的单元是类和类之间沟通用的消息。 // 函数式编程提倡在有限的几种关键数据结构(list、set、map)上运用针对这些数据结构高度优化过的操作,以此构成基本的运转机构。开发者在根据具体用途,插入自己的数据结构和高阶函数去调整机构的运转方式。 // filter 筛选 map 映射 foldleft/reduce 折叠/化约 // 面向对象编程三大特性:继承、封装、多态
-
枚举
// 首字母大写,给枚举类型起一个单数的名字 enum CompassPoint { case north case south case east case west } enum Plant { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune } // 使用switch来匹配枚举值 let direction = CompassPoint.east switch direction { case .north: print("north") case .east: print("east") case .west: print("west") case .south: print("south") } // 遍历枚举的case 但是 枚举要遵循CaseIterable 协议 enum CompassPoint: CaseIterable { case north case south case east case west } let numbers = CompassPoint.allCases.count for dir in CompassPoint.allCases { print(dir) } // 关联值 enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String) } var productCode = Barcode.upc(8, 99, 434, 4) print(productCode) productCode = .qrCode("ddekideoded") switch productCode { case .upc(let num1, let num2, let num3, let num4): print("UPC:\(num1),\(num2),\(num3),\(num4)") case .qrCode(let codeStr): print("QRCode:\(codeStr)") } // 设定原始值 enum ASCIIControlCharacter: Character { case tab = "\t" case lineFeed = "\n" case caeeiageReturn = "\r" } print(ASCIIControlCharacter.tab.rawValue) // 预设原始值 enum Plant: Int { case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune } enum CompassPoint: String { case north case south case east case west } 上面的两个🌰 中第一个行星枚举的默认会比之前的自动加1,第二个方向枚举默认是同名字符串 let possiblePlant = Plant(rawValue: 7) // 递归枚举 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 mul = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
-
类、枚举、结构体添加属性
// struct Point { var x = 0 var y = 0 } struct Size { var width = 0 var height = 0 } struct Rect { var origin: Point var size: Size var center: Point { get { // return Point.init(x: origin.x + size.width/2, y: origin.y + size.height/2) Point(x: origin.x + size.width/2, y: origin.y + size.height/2) } // set(newCenter) { // origin.x = newCenter.x - size.width/2 // origin.y = newCenter.y - size.height/2 // } set { origin.x = newValue.x - size.width/2 origin.y = newValue.y - size.height/2 } } } var rect = Rect(origin: Point(x: 10, y: 10), size: Size(width: 10, height: 10)) print(rect.center) rect.center = Point(x: 12, y: 12) print(rect.origin) // 属性观察者 class StepCounter { var totalSteps: Int = 0 { // willSet(newStep) { // print("will set step \(newStep)") // } willSet { print("will set step \(newValue)") } // didSet(oldStep) { // print("did set step \(oldStep)") // } didSet { print("did set step \(oldValue)") } } } var counter = StepCounter() counter.totalSteps = 100 counter.totalSteps = 200 // 全局变量 var count: Int = 0 { willSet { print("will set count \(newValue)") } didSet { print("did set count \(oldValue)") } } count = 10
-
为类、结构体、枚举添加方法
struct Point { var x = 0 var y = 0 // 实例方法 func printInfo() { print("x = \(x), y = \(y)") } mutating func moveBy(x: Int, y:Int) { self.x += x self.y += y } mutating func move2By(movex:Int, movey:Int) { x += movex y += movey } // 类方法 static func printTypeInfo() { print("a point") } } var p = Point(x: 10, y: 10) p.printInfo() p.moveBy(x: 20, y: 20) p.printInfo() p.move2By(movex: 12, movey: 12) p.printInfo() Point.printTypeInfo()
-
类、结构体、枚举添加下标
struct MAtrix { let rows: Int let columns: Int var grid: [Double] init(rows: Int, colums: Int) { self.rows = rows self.columns = colums grid = Array(repeating: 0.0, count: rows * colums) } subscript(row: Int, column: Int) -> Double { get { return grid[row * columns + column] } set { grid[row * columns + column] = newValue } } } var matrix = MAtrix(rows: 2, colums: 3) matrix[1, 0] = 9.0 print(matrix.grid) enum CompassPoint: Int { case north = 1 case south case east case west static subscript(index: Int) -> CompassPoint{ get { return CompassPoint(rawValue: index)! } } } let direction = CompassPoint[2]
-
类、结构体的初始化
struct Fahehrit { var temperature = 32.0 } struct Fahehrit { var temperature: Double init() { temperature = 32.0 } } // s上面两个🌰 含义一致 class ShoppingListItem { var mame: String? var quantity = 1 var purchased = false } // Swift为所有没有提供初始化器的结构体或类提供了默认的一个初始化器为所有属性提供了默认值 var item = ShoppingListItem() // 自定义的初始化 struct Celsius { var tempertatureInCelsius: Double init(fromeTahrenheit fathrenheit: Double) { tempertatureInCelsius = (fathrenheit - 32.0) / 1.8 } init(fromeKelvin kelvin: Double) { tempertatureInCelsius = kelvin - 273.15 } } let n = Celsius.init(fromeTahrenheit: 212) let b = Celsius.init(fromeKelvin:: 273) // 值类型的初始化器委托 struct Rect { var origin = Point() var size = Size() init() init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center:Point, size: Size) { let originX = center.x - (size.width/2) let originY = center.y - (size.height/2) self.init(origin: Point.init(x: originX, y: originY), size: size) } } // 类的继承和初始化 /* 所有类的存储属性(包括从它的父类继承的所有属性)都必须在初始化期间分配初始值 指定初始化器是类的主要初始化器。指定的初始化器可以初始化所有这个类引用的刷新并且调用合适的父类初始化器来继续这个初始化过程给父类链。 类偏向于少量指定初始化器,并且一个类通常只有一个指定初始化器。指定初始化器是初始化开始并持续初始化过程到父类链的“传送”点。 每个类至少有一个指定初始化器。 便捷初始化器是次要的。 */ /* 指定初始化器必须从它的直系父类调用指定初始化器 便捷初始化器必须从相同的类里调用另一个初始化器 便捷初始化器最终必须调用一个指定初始化器 */ class Person { var name: String var age:Int init(name: String, age: Int) { self.name = name self.age = age } convenience init() { self.init(name: "unNamed", age: 0) } convenience init(age: Int) { self.init(name: "unName", age: age) } } class Teacher: Person { var salary: Int override init(name: String, age: Int) { self.salary = 5000 super.init(name: name, age: age) } init(name: String, age: Int, salary: Int) { // 指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。 // 所以salary初始化在前 self.salary = salary super.init(name: name, age: age) // 初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也 不能引用 self 作为值。 self.test() // 指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做, 指定初始化器赋予的新值将被父类中的初始化器所覆盖。 // 所以父类继承来的name要在初始化后重新赋值 self.name = self.name + "老师" } convenience init(salary: Int) { self.init(name: "unNamed", age: 0, salary: 0) // 便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的 属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。 self.salary = salary + 100 } func test() { print("Dddddd") } deinit { } } // 必要初始化器 class Person { var name: String var age:Int required init(name: String, age: Int) { self.name = name self.age = age } convenience init() { self.init(name: "unNamed", age: 0) } convenience init(age: Int) { self.init(name: "unName", age: age) } } class Teacher: Person { var salary: Int required init(name: String, age: Int) { self.salary = 5000 super.init(name: name, age: age) } init(name: String, age: Int, salary: Int) { // 指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。 // 所以salary初始化在前 self.salary = salary super.init(name: name, age: age) // 初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也 不能引用 self 作为值。 self.test() // 指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做, 指定初始化器赋予的新值将被父类中的初始化器所覆盖。 // 所以父类继承来的name要在初始化后重新赋值 self.name = self.name + "老师" } convenience init(salary: Int) { self.init(name: "unNamed", age: 0, salary: 0) // 便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的 属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。 self.salary = salary + 100 } func test() { print("Dddddd") } deinit { } } // 可失败初始化 class Person { var name: String var age:Int init?(name: String, age: Int) { if age > 200 { return nil } self.name = name self.age = age } }
-
继承
class Vehicle { var currentSepeed: Int = 0 var desc: String { return "run at speed \(currentSepeed)" } // 不可重写 final var descStr: String { return "run at speed \(currentSepeed)" } func makeNoise() { } } class Car: Vehicle { var gear: Int = 0 override var desc: String { return super.desc + " at gear \(gear)" } }
-
多态和类型转换
class MediaItem { var name: String init(name: String) { self.name = name } } class Movie: MediaItem { var director: String init(name: String, director: String) { self.director = director super.init(name: name) } } class Song: MediaItem { var artist: String init(name: String, artist: String) { self.artist = artist super.init(name: name) } } let librarys = [ Movie.init(name: "movie1", director: "director1"), Movie.init(name: "movie2", director: "director2"), Song.init(name: "Song", artist: "art") ] let movies = [ Movie.init(name: "movie1", director: "director1"), Movie.init(name: "movie2", director: "director2"), ] print(type(of: librarys)) print(type(of: movies)) for item in librarys { if let realItem = item as? Movie { print(realItem.director) } }
-
扩展
// extension的能力 1.添加计算实例属性和计算类型属性 2.定义实例方法和类型方法 3.提供新初始化器 4.定义下标 5.定义和使用新内嵌类型 6.使现有的类型遵循某协议 7.扩展可以向一个类型添加新的方法,但是不能重写一有的方法 // 添加属性 extension Double { var km: Double { return self / 1000.0 } } let speed: Double = 3400.0 print(speed.km) // 添加方法 extension Int { func repeatTask(task:() -> ()) { for _ in 0..<self { task() } } } 3.repeatTask { print("task ") } // 添加下标 extension Int { subscript(digitIndex: Int) -> Int { get { var base = 1 for _ in 0..<digitIndex { base *= 10 } return (self / base) % 10 } } } print(134[0]) // 添加内嵌类型 extension Int { enum Kind { case zero case negative case positive } var kind: Kind { get { switch self { case 0: return .zero case let x where x > 0: return .positive default: return .negative } } } } print(0.kind)
-
协议
// 协议可以要求所有遵循该协议的类型提供特定名字和类型的实例属性或类型属性。协议并不会具体说明属性是储存型属性还是计算型属性--它只具体要求属性有特定的名称和类型。协议同时要求一个属性必须明确事可读的或可读的和可写的。 protocol SomeProtocol { var mustBeSettable : Int {get set} var doesNotNeedToBeSettable : Int {get} } protocol FullyName { var fullName: String { get } } protocol Age { var age: Int { get } } struct Person: FullyName { var fullName: String } let john = Person.init(fullName: "John Appless") class Starship: FullyName { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") } } var ncc1701 = Starship.init(name: "Enter", prefix: "USS") struct People: FullyName, Age { var fullName: String var age: Int } let p = People.init(fullName: "zhangsan", age: 30) func wish(to: FullyName & Age) { print("name \(to.fullName) age \(to.age)") } wish(to: p)
-
协议和扩展混合
protocol Name { var name: String { get } } protocol Age { var age: Int { get } } protocol TextRepresentable { var desc: String { get } } struct Person: Name, Age { var name: String var age: Int } extension Person: TextRepresentable { var desc: String { return "name \(name) age \(age)" } } let p = Person.init(name: "tom", age: 33) print(p.desc) extension Array: TextRepresentable where Element: TextRepresentable { var desc: String { let itemDesc = self.map{$0.desc} return itemDesc.joined(separator: ",") } } let array1:[Int] = [] // print(array1.desc) 没有这个属性 let array2 = [Person.init(name: "zhangsna", age: 20), Person.init(name: "lisi", age: 44)] print(array2.desc) let array3 = [3, 5] //print(array3.desc) 没有这个属性 let array4: [Any] = [Person.init(name: "zhangsna", age: 20), 3, Person.init(name: "lisi", age: 44)] //print(array4.desc) 没有这个属性 // 为协议添加扩展 extension Collection where Iterator.Element: TextRepresentable { var desc: String { let itemDesc = self.map{$0.desc} return itemDesc.joined(separator: ",") } } let array1:[Int] = [] // print(array1.desc) 没有这个属性 let array2 = [Person.init(name: "zhangsna", age: 20), Person.init(name: "lisi", age: 44)] print(array2.desc) let array3 = [3, 5] //print(array3.desc) 没有这个属性 let array4: [Any] = [Person.init(name: "zhangsna", age: 20), 3, Person.init(name: "lisi", age: 44)] //print(array4.desc) 没有这个属性
-
面向协议编程
// OOP的缺陷 1.继承机制要求你在开始之前就能设计好整个程序的框架、结构、事物间的连接关系。 2.结构天生对改动有抵抗特性。 3.很多语言不提供多继承 4.OOP带来的可变、不确定、复杂等特征与并行编程中倡导的小型化、核心化、高效化完全背离 // POP // OOP主要关心对象是什么 POP主要关心对象做什么