13 类的构造函数、析构函数和自动引用计数

1. 构造函数

1.1 构造函数的介绍

  • 构造函数类似于OC中的初始化方法:init方法
  • 默认情况下创建一个类时,必然会调用一个构造函数
  • 即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数。
  • 如果是继承自NSObject,可以对父类的构造函数进行重写

1.2 构造函数的基本使用

1.2.1 构造函数的基本使用

  • 类的属性必须有值
  • 如果不是在定义时初始化值,可以在构造函数中赋值
class Person: NSObject {
    var name : String
    var age : Int

    // 重写了NSObject(父类)的构造方法
    override init() {
        name = ""
        age = 0
    }
}

// 创建一个Person对象
let p = Person()

1.2.2 初始化时给属性赋值

  • 很多时候,我们在创建一个对象时就会给属性赋值
  • 可以自定义构造函数
  • 注意:如果自定义了构造函数,会覆盖init()方法.即不再有默认的构造函数
class Person: NSObject {
    var name : String
    var age : Int

    // 自定义构造函数,会覆盖init()函数
    init(name : String, age : Int) {
        self.name = name
        self.age = age
    }
}

// 创建一个Person对象
let p = Person(name: "why", age: 18)

1.2.3 字典转模型(初始化时传入字典)

  • 真实创建对象时,更多的是将字典转成模型
  • 注意:
    • 去字典中取出的是NSObject,任意类型.
    • 可以通过as!转成需要的类型,再赋值(不可以直接赋值)
class Person: NSObject {
    var name : String
    var age : Int

    // 自定义构造函数,会覆盖init()函数
    init(dict : [String : NSObject]) {
        name = dict["name"] as! String
        age = dict["age"] as! Int
    }
}

// 创建一个Person对象
let dict = ["name" : "why", "age" : 18]
let p = Person(dict: dict)

1.2.4 字典转模型(利用KVC转化)

  • 利用KVC字典转模型会更加方便
  • 注意:
    • KVC并不能保证会给所有的属性赋值
    • 因此属性需要有默认值
      • 基本数据类型默认值设置为0
      • 对象或者结构体类型定义为可选类型即可(可选类型没有赋值前为nil)
class Person: NSObject {
    // 结构体或者类的类型,必须是可选类型.因为不能保证一定会赋值
    var name : String?

    // 基本数据类型不能是可选类型,否则KVC无法转化
    var age : Int = 0

    // 自定义构造函数,会覆盖init()函数
    init(dict : [String : NSObject]) {
        // 必须先初始化对象
        super.init()

        // 调用对象的KVC方法字典转模型
        setValuesForKeysWithDictionary(dict)
    }
}

// 创建一个Person对象
let dict = ["name" : "why", "age" : 18]
let p = Person(dict: dict)

2. 析构函数

  • Swift 会自动释放不再需要的实例以释放资源
    • Swift 通过自动引用计数(ARC)处理实例的内存管理
    • 当引用计数为0时,系统会自动调用析构函数(不可以手动调用)
    • 通常在析构函数中释放一些资源(如移除通知等操作)
  • 析构函数的写法
deinit {
    // 执行析构过程
}

示例:

class Person {
    var name : String
    var age : Int

    init(name : String, age : Int) {
        self.name = name
        self.age = age
    }

    deinit {
        print("Person-deinit")
    }
}

var p : Person? = Person(name: "why", age: 18)
p = nil

3. 自动引用计数

3.1 工作机制

  • Swift和OC一样,采用自动引用计数来管理内容
  • 当有一个强引用指向某一个对象时,该对象的引用计数会自动+1
  • 当该强引用消失时,引用计数会自动-1
  • 当引用计数为0时,该对象会被销毁

3.2循环引用

  • 在通常情况下,ARC是会自动帮助我们管理内存的
  • 但是在开发中我们经常会出现循环引用的问题,比如下面的示例
    • Student对Book对象有一个强引用
    • 而Book对Student有一个强引用
    • 在两个对象都指向nil时,依然不会被销毁,就形成了循环引用
// 1.创建类
class Student {
    var book : Book?

    deinit {
        print("Student -- deinit")
    }
}

class Book {
    var owner : Student?

    deinit {
        print("Book -- deinit")
    }
}

// 2.创建对象
var stu : Student? = Student()
var book : Book? = Book()

// 3.相互引用
stu?.book = book
book?.owner = stu

// 4.对象置nil
stu = nil
book = nil
  • 解决方案
    • swift提供了两种解决方案
      • weak : 和OC中的__weak一样是一个弱引用.当指向的对象销毁时,会自动将指针指向nil
      • unowned : 和OC中的__unsafe_unretained.当对象销毁时依然指向原来的位置(容易引起野指针)
// 1.创建类
class Student {
    weak var book : Book?
    // unowned var book : Book = Book()

    deinit {
        print("Student -- deinit")
    }
}

class Book {
    var owner : Student?

    deinit {
        print("Book -- deinit")
    }
}

// 2.创建对象
var stu : Student? = Student()
var book : Book? = Book()

// 3.相互引用
stu?.book = book!
book?.owner = stu

// 4.对象置nil
stu = nil
book = nil
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容