Swift构造方法

  • 构造方法作用:对实例对象的内容进行初始化
    Swift要求类或者结构体中的存储属性(非lazy属性)在对象构造完毕后要有初始化值
    语法:
init(参数列表){ 初始化代码 }

注意

  1. 构造方法的作用仅仅是用于初始化属性, 而不是分配内存, 分配内存是系统帮我们做的
  2. 构造方法是隐式调用的, 通过类名称() 形成创建一个对象就会隐式调用 init() 构造方法
  3. 如果所有的存储属性都有默认值, 可以不提供构造方法, 系统会提供一个隐式的构造方法;
  4. 如果存储属性可以提供默认值, 那么提倡大家使用设置默认值的方法, 这样可以简化代码,不用写构造方法
class Person {
    var name: String = "hjq"
//    var age: Int = 20
    var age:Int
    func description() -> String {
        return "name = \(name) age = \(age)"
    }

    init() {
        print("init")
        age = 30
    }
}

// 1.分配内存; 2.初始化name和age; 3.构造方法是隐式调用的
var p = Person()
print(p.description())
print(p.age)
  • 带参数的构造方法
class Person2 {
    var name:String
    var age:Int
    func description() -> String {
        return "name = \(name) age = \(age)"
    }
   
    init(age:Int, name:String)
    {
        self.name = name
        self.age = age
    }
    func setName(name:String, age:Int)
    {
        self.name = name
        self.age = age
    }
}
var p2 = Person2(age: 25, name: "hjq")
p2.setName(name: "hjq", age: 30)
print(p2.description())

以上存储属性都没有提供默认值,必须提供构造方法,而构造方法是带参数的,所以创建对象时必须带参数来初始化存储属性,而不能用Person2()

  • 结构体和构造方法
struct Rect {
    var width:Double
    var height:Double
    /*
    // 系统默认会提供一个类似的方法
    init(width:Double, height:Double)
    {
        self.width = width
        self.height = height
    }
    */
}
var r = Rect(width: 20, height: 20)

以上存储属性都没有默认值,故必须用默认的逐一构造器初始化结构体,不存在Rect()的方式初始化结构体。
如果在结构体中自定义了构造方法, 那么系统不会生成默认的逐一构造器。
如果给存储属性提供了默认值, 系统还是会提供默认的逐一构造器

  • 构造器代理: 构造方法之间的相互调用,即在构造方法中可以调用其他构造方法来完成实例的构造。好处减少不必要的代码
struct Rect2 {
    var width:Double, height:Double
    init(width:Double, height:Double)
    {
        self.width = width
        self.height = height
    }
    init()
    {
//        self.width = 0.0
//        self.height = 0.0
        //构造器代理
        self.init(width: 0, height: 0)
    }
    func show()
    {
        print("width = \(width) height = \(height)")
    }
}
var r2 = Rect2()
r2.show()
var r3 = Rect2(width: 100, height: 100)
r3.show()
  • 指定构造器与便利构造器
    • 结构体是值类型,类是引用类型。引用类型的init()方法前必须加convenience关键字,这样的构造器被称为便利构造器。而带参数的init(name:String, age:Int)方法被称为指定构造器。
    • 便利构造器中必须出现self.init。
    • 指定构造器和便利构造器不能是相同参数
class Person {
    var name:String
    var age:Int
    //指定构造方法都是以init开头
    init(name:String, age:Int)
    {
        self.name = name
        self.age = age
    }
    //1.如果是值类型没问题, 称之为构造器代理;
    //2.但是如果是引用类型会报错, 需要在前面加上 convenience关键字;
    //3.被convenience关键字修饰的构造方法称之为便利构造器, 通过调用其他构造方法来初始化;
    //4.反而言之, 便利构造器中一定是调用其他构造方法初始化的, 一定要出现self.init
    convenience init()
    {
        self.init(name: "hjq", age: 26)
    }
    //类可以拥有多个构造方法
    init(name:String)
    {
        self.name = name
        self.age = 0
        //不能再指定构造方法中调用便利构造器方法
        //换言之,指定构造方法中不能出现self.init
//        self.init()
    }
    
    convenience init(age:Int)
    {
        //可以在便利构造器中调用指定构造器
//        self.init(name: "hjq", age: 24)
        self.init()
    }
    // 便利构造器不能和指定构造器同名
    //    convenience init(name:String)
    //    {
    //    }
}
  • 派生类的构造方法
class Man {
    var name:String
    //指定构造器
    init(name:String)
    {
        self.name = name
    }
    convenience init(){
        self.init(name: "hjq")
    }
}
class SuperMan: Man {
    var age:Int
    
    // 注意:
    // 1.默认情况下基类的构造方法不会被继承
    // 2.基类的存储属性只能通过基类的构造方法初始化
    // 3.初始化存储属性时必须先初始化当前类再初始化父类
    // 4.不能通过便利构造器初始化父类, 只能通过调用指定构造器初始化父类
    //指定构造器
    init(age:Int) {
        self.age = age
        super.init(name: "han")    //必须调用父类的指定构造器
//        super.init()    //不能调用父类的便利构造器
    }
}
  • 构造器间的调用规则
    • 1.子类指定构造器必须调用其直接父类的"指定构造器"
    • 2.子类便利构造器必须调用当前类中的其他构造器(指定或者便利),且最终必须调用一个指定构造器结束(无论指定还是便利, 最终肯定调用一个指定构造器)
    • 3.子类指定构造器必须出现super.init,便利构造器不要super.init
class Man2 {
    var name:String
    //指定构造器
    init(name:String) {
        self.name = name
    }
    convenience init(){
        self.init(name: "HaRi")
    }
}
class SuperMan2: Man2 {
    var age:Int
    //指定构造器
    init(age:Int) {
        self.age = age
        super.init(name: "xiaohange")
    }
    convenience init()
    {
        self.init(age: 25)
    }
    convenience  init(name: String, age: Int) {
        //调用当前类构造器一定能够初始化所有属性
//        self.init(age: 30)
        //便利构造器中只能通过self.init来初始化, 不能使用 super.init
        //因为调用父类构造器不一定完全初始化所有属性(子类持有)
//        super.init(name: "han")
        self.init()
    }
}
  • 两段式构造。构造过程可以划分为两个阶段:
    1.确保当前类和父类所有存储属性都被初始化
    2.做一些其他初始化操作
    好处:可以防止属性在被初始化前访问
class Man3 {
    var name:String
    //指定构造方法
    init(name:String) {
        self.name = name
    }
    //便利构造方法
    convenience init(){
        self.init(name: "hello world")
    }
}

class SuperMan3: Man3 {
    var age:Int
    init(age:Int) {
        print("SuperMan第一阶段开始")
        //对子类引入的属性初始化
        self.age = age
        
        //代码会报错, 因为调用self.name之前还没有对父类的name进行初始化
        //即便在这个地方修改, 也会被后面的初始化语句覆盖
//        if age > 30 {
//            self.name = "hjq"
//        }
        //对父类引入的属性进行初始化
        super.init(name: "han")
        
        print("SuperMan第二阶段开始")
        if age > 30 {
            self.name = "hello xiaohange"
        }
    }
}
  • 必须构造器。父类构造器加了required关键字,则子类必须重写该构造器,且带上required关键字
class Person7 {
    var name:String
    required init(name:String){
        self.name = name
    }
}
class SuperMan7: Person7 {
    var age:Int
    init() {
        self.age = 24
        super.init(name: "hjq")
    }
    required init(name: String) {
        self.age = 24
        super.init(name: name)
    }
}
var sm7 = SuperMan7(name: "hjq")
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343