前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >19.Swift学习之构造函数与析构函数

19.Swift学习之构造函数与析构函数

作者头像
YungFan
发布2018-11-08 10:42:15
1K0
发布2018-11-08 10:42:15
举报
文章被收录于专栏:学海无涯
重要说明
  • 本文中提到的构造函数,在很多书中有其他的说法,如构造器,构造方法,初始化,初始函数等
  • 本文中提到的析构函数,在很多书中有其他的说法,如反构造器,析构方法,反初始化,反初始函数等
构造函数的介绍
  • 构造函数用于初始化一个类的实例(创建对象)
  • 默认情况下载创建一个类时,必然会调用一个构造函数
  • 即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数
  • 如果是继承自NSObject,可以对父类的构造函数进行重写
默认构造函数
  • 在创建类和结构体的实例时必须为所有的存储属性设置一个合适的初始值,如果不是在定义时初始化值,可以在构造函数中赋值
  • 构造函数就像一个没有形式参数的实例方法,使用 init 关键字来写
代码语言:javascript
复制
init() {
    // perform some initialization here
}
代码语言:javascript
复制
class Person: NSObject {
    var name : String
    var age : Int

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

// 创建一个Person对象
let p = Person()
自定义构造函数
  • 很多时候,我们在创建一个对象时就会给属性赋值
  • 可以自定义构造函数
  • 注意:如果自定义了构造函数,会覆盖init()方法.即不在有默认的构造函数
代码语言:javascript
复制
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)
结构体类型的成员构造函数
  • 如果结构体类型中没有定义任何自定义构造函数,它会自动获得一个成员构造函数。不同于默认构造函数,结构体会接收成员构造函数即使它的存储属性没有默认值
代码语言:javascript
复制
//定义了一个名为 Size 有两个属性分别是 width 和 height 的结构体,这两个属性通过分配默认值 0.0 ,从而被推断为 Double 类型
struct Size {
    var width = 0.0, height = 0.0
}
//Size 结构体自动接收一个 init(width:heght:) 构造函数
let twoByTwo = Size(width: 2.0, height: 2.0)
值类型的构造函数委托
  • 构造函数可以调用其他构造函数来执行部分实例的初始化。这个过程,就是所谓的构造函数委托。
  • 构造函数的运作,对于值类型和类类型是不同的。
  • 值类型(结构体和枚举)不支持继承,所以他它们的构造函数委托的过程相当简单。
  • 注意如果为值类型定义了自定义构造函数,就不能访问默认构造函数或者是成员构造函数
类的继承和初始化
  • 所有类的存储属性——包括从它的父类继承的所有属性都必须在初始化期间分配初始值。
  • Swift 为类类型定义了两种构造函数以确保所有的存储属性接收一个初始值。这些就是所谓的指定构造函数和便捷构造函数
    • 指定构造函数是类的主要构造函数。指定构造函数可以初始化所有那个类引用的属性并且调用合适的父类构造函数来继续这个初始化过程给父类链
    • 类偏向于少量指定构造函数,并且一个类通常只有一个指定构造函数
    • 每个类至少得有一个指定构造函数
    • 便捷构造函数是次要的,为一个类支持构造函数。你可以在相同的类里定义一个便捷构造函数来调用一个指定的构造函数作为便捷构造函数来给指定构造函数设置默认形式参数。
代码语言:javascript
复制
//类的指定构造函数
init(parameters) {
    statements
}
//便捷构造函数有着相同的书写方式,但是要用 convenience 修饰符放到 init 关键字前,用空格隔开:
convenience init(parameters) {
    statements
}
类类型的构造函数委托
  • 为了简化指定和便捷构造函数之间的调用关系,Swift 在构造函数之间的委托调用有下面的三个规则:
    • 规则 1——指定构造函数必须从它的直系父类调用指定构造函数。
    • 规则 2——便捷构造函数必须从相同的类里调用另一个构造函数。
    • 规则 3——便捷构造函数最终必须调用一个指定构造函数。
  • 简单记忆的这些规则的方法如下:
    • 指定构造函数必须总是向上委托。
    • 便捷构造函数必须总是横向委托。

    类类型的构造函数委托

构造函数的继承与重写
  • 在Swift中,子类的构造函数有两种来源,首先是自己拥有的构造函数,其次是从父类中继承过来的构造函数。但是,比不是所有父类构造函数都能够被子类继承。子类继承父类的构造函数是有条件的,遵守以下2个规则:
    • 规则1——如果子类没有定义任何指定初始化器,它会自动继承父类所有的指定初始化器
    • 规则2——如果子类提供了所有父类指定初始化器的实现——要么是通过规则1继承来的,要么通过在定义中提供自定义实现的,那么它自动继承所有的父类便捷初始化器。
  • 如果一个子类中任意的构造器和父类的便利构造器一模一样, 不算重写
  • 一个例子
代码语言:javascript
复制
class Person {   
    var name: String!
    var weight: Double  
    init(name: String) {
        self.name = name
        self.weight = 0.0
    } 
    // 定义指定构造器
    init(name: String, weight: Double) {
        self.name = name
        self.weight = weight
    }
     
    // 定义便利构造器(使用convenience修饰)
    convenience init(n name: String, w weight: Double) {
        // 便利构造器必须调用同类中的指定构造器
        self.init(name: name, weight: weight)
    }
     
    convenience init(showStr: String) {
        self.init(name: "", weight: 0.0)
        print(showStr)
    }
}
 
class Man: Person {
    var sex: String = "男"   
    override init(name: String) {
        // 子类的指定构造器中必须调用父类的指定构造器
        super.init(name: name)
        self.name = name
        self.weight = 0.0
    }
    override init(name: String, weight: Double) {
        super.init(name: name, weight: weight)
        self.name = name
        self.weight = weight
    }   
    // 定义指定构造器与父类的便利构造器一样, 这里不算重写
    convenience init(showStr: String) {
        self.init(name: "", weight: 0.0)
        print(showStr)
    }
}
 
var manA = Man(name: "ZhangSan", weight: 62.0)
var manB = Man(showStr: "Hello Swift")
可失败构造函数
  • 定义类、结构体或枚举初始化时可以失败
  • 失败可能由以下几种方式触发,包括给初始化传入无效的形式参数值,或缺少某种外部所需的资源,又或是其他阻止初始化的情况
  • 为了处理这种可能,在类、结构体或枚举中定义一个或多个可失败的构造函数。通过在 init 关键字后面添加问号init?
代码语言:javascript
复制
struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}
let someCreature = Animal(species: "Giraffe")
if let giraffe = someCreature {
    print("An animal was initialized with a species of \(giraffe.species)")
}
必要构造函数
  • 在类的构造函数前添加required 修饰符来表明所有该类的子类都必须实现该构造函数
  • 当子类重写父类的必要构造函数时,必须在子类的构造函数前添加 required 修饰符以确保当其它类继承该子类时,该构造函数同为必要构造函数
  • 在重写父类的必要构造函数时,不需要添加 override 修饰符
代码语言:javascript
复制
class SomeClass {
    required init() {
    }
}
代码语言:javascript
复制
class SomeSubclass: SomeClass {
    required init() {
    }
}
析构函数
  • Swift 会自动释放不再需要的实例以释放资源
    • Swift 通过自动引用计数(ARC)处理实例的内存管理
    • 当引用计数为0时,系统会自动调用析构函数(不可以手动调用)
    • 通常在析构函数中释放一些资源(如移除通知等操作)
  • 析构函数的写法
代码语言:javascript
复制
deinit {
    // 执行析构过程
}
示例练习
代码语言:javascript
复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.10.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 重要说明
  • 构造函数的介绍
  • 默认构造函数
    • 自定义构造函数
    • 结构体类型的成员构造函数
    • 值类型的构造函数委托
    • 类的继承和初始化
    • 类类型的构造函数委托
    • 构造函数的继承与重写
    • 可失败构造函数
    • 必要构造函数
    • 析构函数
      • 示例练习
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档