Swift笔记之构造、析构、as、Any和AnyObject

379 阅读5分钟

方法

  • 实例方法
    • 在实例方法中修改值类型
      struct area {
      var length = 1
      var breadth = 1
      func area() -> Int {
          return length * breadth
      }
      //    在方法结束时给隐含属性self,赋值一个全新的实例,替换原来的
      mutating func scaleBy(res: Int) {
              length *= res
          }
      }
      
  • 类方法
    • 结构体和枚举用static声明,类用class声明

下标脚本

  • 使用subscript关键字,显示声明入参和返回值类型
  • 使用subscript后,实例可以x[0]的形式,对实例进行访问和赋值
    struct SomeStruct {
        var decrementer: Int
        subscript(index: Int) -> Int {
            get {
                return decrementer / index
            }
            set {
                self.decrementer = newValue
            }
        }
    }
    
    let division = SomeStruct(decrementer: 100)
    print("100 除以 9 等于 \(division[9])")
    

Swift构造过程

  • 使用init()方法构造,不需要返回值
  • 可以再定义init()方法时,提供构造参数
    struct SomeStruct {
        var decrementer: Int
        // _下划线描述外部参数名,调用的时候可以省略
        init(_ decrementer: Int) {
            self.decrementer = decrementer
        }
    }
    
    let division = SomeStruct(12)
    
  • 如果你在定义构造器时没有提供参数的外部名字,Swift会为每个构造器的参数自动生成一个跟内部名字相通的外部名
  • 可选属性,初始值为nil
  • 常量类型的值可以再定义它的类的构造过程中修改,不能再子类修改
  • 默认构造器将创建一个所有属性值都设置为默认值的实例
  • struct的逐一成员构造器
    struct SomeStruct {
        var decrementer: Int
        var index: Int
    }
    
    var area = SomeStruct(decrementer: 10, index: 8)
    
  • 值类型的构造器代理
    • 构造器可以通过其他构造器来完成实例的部分构造构成
    struct Size {
    var width = 0.0, height = 0.0
    }
    
    struct Point {
        var x = 0.0, y = 0.0
    }
    
    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 originalX = center.x - size.width / 2.0
            let originalY = center.y - size.height / 2.0
            self.init(origin: Point(x: originalX, y: originalY), size: size)
        }
    }
    
  • 类的指定构造器init(),每一个类都必须拥有至少一个指定构造器
  • 类的便利构造器override convenience init(no1: Int)
  • 子类不会继承父类的构造器
    class SuperClass {
        var name: String
        init(name: String) {
            self.name = name
        }
        convenience init() {
            self.init(name: "匿名")
        }
    }
    
    let main = SuperClass(name: "Runoob")
    
    let main1 = SuperClass()  // name是"匿名"
    
  • init?(name: String)或者init!(name: String)可失败构造器
    enum TemperatureUnit {
        case Kelvin, Celsius, Fahrenheit
        init?(symbol: Character){
            switch symbol {
            case "K":
                self = .Kelvin
            case "C":
                self = .Celsius
            case "F":
                self = .Fahrenheit
            default:
                return nil
            }
        }
    }
    
  • 子类覆盖一个可失败构造器

Swift析构过程

  • deinit
    • 类实例被释放之前,析构函数立即被调用
    • 只有类类型有deinit
      var counter = 0      //引用计数
      class BaseClass {
          init() {
              counter += 1
          }
          // 每个类只有一个析构函数,不带任何参数和括号
          deinit {
              counter -= 1
          }
      }
      

可选链

  • 使用if语句判断是否可以调用
    //调用成功返回Void,调用失败返回nil
    if ((john.residence?.printNumberOfRooms()) != nil) {
        print("输出房间号")
    } else {
        print("无法输出房间号")
    }
    
  • 使用可选链调用下标脚本
    // 问号在方括号前面
    if let firstRoomName = john.residence?[0].name {
        print("第一个房间名 \(firstRoomName).")
    } else {
        print("无法检索到房间")
    }
    
  • 访问可选类型的下标
    var  test = ["Dave": [87,89]]
    test["Dave"]?[0] = 91
    

ARC

  • 循环引用
    • 两个类实例保持对对方的强引用
    • 解决--弱引用和无主引用
    class Person {
      var apartment: Apartment?
      deinit {
          print("person")
      }
    }
    
    class Apartment {
        // 弱引用
        weak var tenant: Person?
        //无主引用
    //    unowned var tenant: Person?
        deinit {
            print("apartment")
        }
    }
    var runoob: Person?
    var number73: Apartment?
    runoob = Person()
    number73 = Apartment()
    
    runoob?.apartment = number73
    number73?.tenant = runoob
    
    runoob = nil
    number73 = nil			
    
    • 闭包循环引用
      • 如果再闭包中引用self,这个闭包必须是lazy
        class HTMLElement {
        let name: String
        let text: String?
        // 如果lazy属性是闭包调用的结果,那么不考虑循环引用问题
        lazy var getAge: String = {
            self.name
        }()
        //
        //    lazy var asHTML: () -> String = {
        //        // unowned 方式,self是assign方式,有可能出现野指针
        ////        [unowned self] in    // 闭包和捕获的实例总是同时销毁时,用无主引用
        //        return self.name
        //        // weak方式
        ////        [weak self] in        // 当捕获的引用有可能会是nil时,将闭包内的捕获定义为弱引用
        ////        return (self?.text ?? "")
        //        //
        //
        //    }
            init(name: String, text: String? = nil) {
                self.name = name
                self.text = text
            }
        //
            deinit {
                print("\(name) is being deinitialized")
            }
        }
        
        var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello world")
        
        print(paragraph!.getAge)
        paragraph = nil	
        
    • @escaping
      • 非逃逸闭包,闭包调用发生在函数结束之前
      • 逃逸闭包,闭包调用发生在函数结束之后,闭包调用逃离了函数的作用域,需要用@escaping声明
      • 逃逸闭包不可以捕获inout类型的参数
      typealias Closure = () -> ()
      
      func someMethod(block: Closure) {
          block()
      }
      
      var globalClosure : Closure?
      
      // 逃逸闭包
      func escapingMethod(block: @escaping Closure) {
          globalClosure = block
      }
      
      // 逃逸闭包
      func escapingMethod2(block: @escaping Closure, value: inout Int) {
          DispatchQueue.global().async {
              // 逃逸闭包不可以捕获inout参数
      //        func plus() {
      //            value + 1
      //        }
              block()
          }
      }
      

类型转换

  • is
    • 检查实例是否属于特定的类型
      class Subjects {
      
      }
      class Maths: Subjects {
      
      }
      class Chemistry: Subjects {
      
      }
      var p: Subjects
      
      p = Maths()
      
      if p is Subjects {
          print("Maths")
      }
      
  • as
    • as 子类向父类转
      let sub = Subjects()
      let mat = Maths()
      // 子类向父类转
      let asMat = mat as Subjects
      
    • as 用在switch语句中,检测对象类型,对对象类型处理
      let sa = [Chemistry(), Maths()]
      for item in sa {
          // 用在switch语句中,检测对象类型,对对象类型处理
          switch item {
              case _ as Maths:
                  print("Maths")
              case _ as Chemistry:
              print("Chemistry")
              default:
                  break
          }
      }
      
  • as?
    • 向下转型(DownCasting),父类向子类转换
    • 转换不成功时返回nil, 转换成功时返回的是可选类型
      let sa = [Chemistry(), Maths()]
      for item in sa {
          if let show = item as? Chemistry  {
              print("化学 \(show)")
          } else if let example = item as? Maths {
              print("\(example)")
          }
      }
      
  • as!
    • 向下转型(DownCasting),父类向子类转换
    • 转换不成功时,报 runtime 运行错误。
      let sub: Subjects = Maths()
      let mat = sub as! Maths
      
  • Any
    • 可以表示任何类型,包括方法类型
      var exaAny = [Any]()
      exaAny.append(2)
      exaAny.append("string")
      exaAny.append(2.3)
      
      for item in exaAny {
          switch item {
          case let someInt as Int:
              print("\(someInt)")
          case let someString as String:
              print("\(someString)")
          case let someDouble as Double:
              print("\(someDouble)")
          default:
              print("none")
          }
      }
      
  • AnyObject
    • 可以代表任何class类型的实例
      var exaAnyObject = [AnyObject]()
      exaAnyObject.append(Subjects())
      exaAnyObject.append(Maths())