Swfit-04.类,元类,错误处理,泛型,拓展。。。

2020-12-18  本文已影响0人  Fight_ing
tree_23.jpg
class Person {}
class Student : Person {}
var perType: Person.Type = Person.self 
var stuType: Student.Type = Student.self 
perType = Student.self

var anyType: AnyObject.Type = Person.self 
anyType = Student.self

public typealias AnyClass = AnyObject.Type 
var anyType2: AnyClass = Person.self 
anyType2 = Student.self

var per = Person()
var perType = type(of: per) // Person.self 
print(Person.self == type(of: per)) // true

  
//元类型的应用
class Animal { required init() {} } 
class Cat : Animal {}
class Dog : Animal {}
class Pig : Animal {}
func create(_ clses: [Animal.Type]) -> [Animal] { 
    var arr = [Animal]()
    for cls in clses {
        arr.append(cls.init()) 
    }
    return arr 
}
print(create([Cat.self, Dog.self, Pig.self]))
Self
// Self代表当前类型
class Person {
    var age = 1
    static var count = 2
    func run() {
        print(self.age) // 1
        print(Self.count) // 2 等价于Person.count
    }
}
// Self一般用作返回值类型,限定返回值跟方法调用者必须是同一类型(也可以作为参数类型)
protocol Runnable { 
    func test() -> Self
}
class Person : Runnable {
    required init() {}
    func test() -> Self { 
        type(of: self).init() 
    } 
}
class Student : Person {}
var p = Person() 

// Person 
print(p.test())

var stu = Student() 
// Student 
print(stu.test())
// Swift中可以通过Error协议自定义运行时的错误信息
enum SomeError : Error {
    case illegalArg(String) 
    case outOfBounds(Int, Int) 
    case outOfMemory
}
// 函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明
 func divide(_ num1: Int, _ num2: Int) throws -> Int { 
    if num2 == 0 {
        throw SomeError.illegalArg("0不能作为除数")
    }
    return num1 / num2
}
// 需要使用try调用可能会抛出Error的函数
var result = try divide(20, 10)

1 通过do-catch捕捉Error
2 不捕捉Error,在当前函数增加throws声明,Error将自动抛给上层函数, 如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止
3 可以使用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error

func exec(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows { 
    print(try fn(num1, num2))
}
// Fatal error: Error raised at top level
try exec(divide, 20, 0)
  1. defer语句:用来定义以任何方式(抛错误、return等)离开代码块前必须要执行的代码
  2. defer语句将延迟至当前作用域结束之前执行
// defer语句的执行顺序与定义顺序相反
func test() {
    defer { fn1() }
    defer { fn2() }
}
test()
// fn2
// fn1
  1. 很多编程语言都有断言机制:不符合指定条件就抛出运行时错误,常用于调试(Debug)阶段的条件判断
  2. 默认情况下,Swift的断言只会在Debug模式下生效,Release模式下会忽略

增加Swift Flags修改断言的默认行为
p-assert-config Release:强制关闭断言
p-assert-config Debug:强制开启断言

  1. 如果遇到严重问题,希望结束程序运行时,可以直接使用fatalError函数抛出错误(这是无法通过do-catch捕捉的错误)
  2. 使用了fatalError函数,就不需要再写return
  3. 在某些不得不实现、但不希望别人调用的方法,可以考虑内部使用fatalError函数
  // 字符串长度 <= 0xF(15),字符串内容直接存放在str1变量的内存中。(类似OC中的tagger pointer 技术)
 var str1 = "0123456789"
 
 // 字符串长度 > 0xF,字符串内容存放在__TEXT.cstring中(常量区)
 // 字符串的地址值信息存放在str2变量的后8个字节中
 var str2 = "0123456789ABCDEF"
 
 // 由于字符串长度 <= 0xF,所以字符串内容依然存放在str1变量的内存中
 str1.append("ABCDE")
 // 开辟堆空间
 str1.append("F")
 
 // 开辟堆空间
 str2.append("G")
  1. Swift的算数运算符出现溢出时会抛出运行时错误
  2. Swift有溢出运算符(&+、&-、&*),用来支持溢出运算
     var min = UInt8.min
     print(min &- 1) // 255, Int8.max
     var max = UInt8.max
     print(max &+ 1) // 0, Int8.min 
     print(max &* 2) // 254, 等价于 max &+ max
     // 逐渐递增
     UInt8.min 0
     UInt8.max 255
    
    • 运算符重载(Operator Overload):
      • 类、结构体、枚举可以为现有的运算符提供自定义的实现,这个操作叫做:运算符重载
        struct Point : Equatable {
         var x = 0, y = 0
         static func + (p1: Point, p2: Point) -> Point {
             Point(x: p1.x + p2.x, y: p1.y + p2.y)
         }
         static func - (p1: Point, p2: Point) -> Point {
             Point(x: p1.x - p2.x, y: p1.y - p2.y)
         }
         static prefix func - (p: Point) -> Point {
             Point(x: -p.x, y: -p.y)
         }
         static func += (p1: inout Point, p2: Point) {
             p1 = p1 + p2
         }
         static prefix func ++ (p: inout Point) -> Point {
             p += Point(x: 1, y: 1)
             return p
         }
         static postfix func ++ (p: inout Point) -> Point {
             let tmp = p
             p += Point(x: 1, y: 1)
             return tmp
         }
     }
    
    • Equatable:
      • 要想得知2个实例是否等价,一般做法是遵守Equatable 协议,重载== 运算符
      • 与此同时,等价于重载了 != 运算符
      • Swift为以下类型提供默认的Equatable 实现
      1. 没有关联类型的枚举
      2. 只拥有遵守 Equatable 协议关联类型的枚举
      3. 只拥有遵守 Equatable 协议存储属性的结构体
      • 引用类型比较存储的地址值是否相等(是否引用着同一个对象),使用恒等运算符=== 、!==
    • Comparable
      • 要想比较2个实例的大小,一般做法是: 1.遵守 Comparable 协议 2.重载相应的运算符
      // score大的比较大,若score相等,age小的比较大 
      struct Student : Comparable {
         var age: Int
         var score: Int
         init(score: Int, age: Int) {
         self.score = score
         self.age = age 
         }
         static func < (lhs: Student, rhs: Student) -> Bool { 
             (lhs.score < rhs.score)
             || (lhs.score == rhs.score && lhs.age > rhs.age)
         }
         static func > (lhs: Student, rhs: Student) -> Bool {
             (lhs.score > rhs.score)
             || (lhs.score == rhs.score && lhs.age < rhs.age)
         }
         static func <= (lhs: Student, rhs: Student) -> Bool {
             !(lhs > rhs) 
         }
         static func >= (lhs: Student, rhs: Student) -> Bool { 
             !(lhs < rhs)
         } 
     }
    
     var stu1 = Student(score: 100, age: 20) 
     var stu2 = Student(score: 98, age: 18) 
     var stu3 = Student(score: 100, age: 20) 
     print(stu1 > stu2) // true
     print(stu1 >= stu2) // true
     print(stu1 >= stu3) // true
     print(stu1 <= stu3) // true
     print(stu2 < stu1) // true
     print(stu2 <= stu1) // true
    
    
    • 自定义运算符(Custom Operator)
      • 可以自定义新的运算符:在全局作用域使用operator进行声明
     prefix operator 前缀运算符
     postfix operator 后缀运算符
     infix operator 中缀运算符 : 优先级组
     precedencegroup 优先级组 {
         associativity: 结合性(left\right\none)
         higherThan: 比谁的优先级高
         lowerThan: 比谁的优先级低
         assignment: true代表在可选链操作中拥有跟赋值运算符一样的优先级
     }
    
     prefix operator +++
     infix operator +- : PlusMinusPrecedence 
     precedencegroup PlusMinusPrecedence {
         associativity: none
         higherThan: AdditionPrecedence 
         lowerThan: MultiplicationPrecedence 
         assignment: true
     }
    
    Apple文档参考1
    Apple文档参考2
    • 示例:
     struct Point {
         var x: Int, y: Int
         static prefix func +++ (point: inout Point) -> Point {
             point = Point(x: point.x + point.x, y: point.y + point.y)
             return point
         }
         static func +- (left: Point, right: Point) -> Point { 
             return Point(x: left.x + right.x, y: left.y - right.y)
         }
         static func +- (left: Point?, right: Point) -> Point {
             print("+-")
             return Point(x: left?.x ?? 0 + right.x, y: left?.y ?? 0 - right.y) 
         }
     }
     struct Person {
         var point: Point
     }
     var person: Person? = nil 
     person?.point +- Point(x: 10, y: 20)
    

open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
fileprivate:只允许在定义实体的源文件中访问
private:只允许在定义实体的封闭声明中访问
绝大部分实体默认都是internal 级别

1.元祖,泛型都以最低那个为准
2.协议实现不得小于协议和类中的较小的那个
3.枚举不能每项单独定义
4.public 限定作用域内部默认是internal
5.required初始化器 ≥ 它的默认访问级别

内存访问冲突会在两个访问满足下列条件时发生:
至少一个是写入操作
它们访问的是同一块内存
它们的访问时间重叠(比如在同一个函数内)

    // 不存在内存访问冲突
    func plus(_ num: inout Int) -> Int { num + 1 } var number = 1
    number = plus(&number)

    // 存在内存访问冲突
    // Simultaneous accesses to 0x0, but modification requires exclusive access var step = 1
    func increment(_ num: inout Int) { num += step }
    increment(&step)

    // 解决内存访问冲突
    var copyOfStep = step 
    increment(&copyOfStep) 
    step = copyOfStep

以上均根据CoderMJLee老师的视频及资料整理,祝小码哥教育越来越好,特此感谢!!!

如有侵权,请联系删除fm939071955@163.com

上一篇 下一篇

猜你喜欢

热点阅读