Swift 的构造器(一)

前言

      本文主要是Swift的构造器相关知识,另加少部分的OC中的init方法(还有少许Java相关的构造方法),通过两者的对比来加深对Swift构造器的理解,毕竟Swift是要淘汰的OC的,所以主要研究Swift也是必然。

指定构造器和便利构造器

        Swift构造器分为两类,一类是指定构造器(Designated Initializer),另一类是便利构造器(Convenience Initializer)。

      指定构造器

        指定构造器在一个类中必须至少有一个, 因为它是类的最主要构造器,没有之一,所有类的实例的初始化必然会调用指定构造器。以init开头,参数名、参数列表可以依照实际情况编写。当没有自定义指定构造器时,系统会自动生成一个不带参数的默认构造器,不带参数的默认构造器,意味着类的定义中,成员变量一定要赋上默认值。当有自定义指定构造器时,类的定义中,成员变量可以没有默认值,但是会在调用指定构造器时给其赋值,并且赋值时机要在调用父类的指定构造器之前(如果这个类有父类时)。举个例子,先定义一个基类。

```

class Person {

      // 成员变量 name 、 sex都是没有赋值

       var name:String

       var sex:String

       init(name:String, sex:String) {

            // 在指定构造器中给成员变量赋值

            self.name = name

            self.sex = sex

       }

}

```

  在这个基类Person中,成员变量 name和sex在定义时都没有赋值,只是指定数据类型,相关的赋值是在指定构造器init(name:String, sex:String)中完成的。如果把Person类改成下面这样

```

   // 这是个错误的定义

    class Person {

          var name:String

          var sex:String

    }

```

这个时候Xcode直接报错:

这里报错第一行显示是Person没有构造器,其他行显示name和sex没有初始值,其实本质来说,是因为成员变量在Swift中已经不是自动生成默认值,需要程序员自己指定。这里就需要提到一个不管是在Swift或者OC,还是Java或是其他面向对象的语言都有的概念:某个类的实例被创建,其成员变量一定要有值。在上面的错误定义中,因为Swift不再为成员变量自动生成默认值,如果程序员再不指定,这样在创建实例时成员变量会没有值,结果当然是直接就报错了。如果我们像下面这样稍微改动一下:

```

class Person {

      var name:String="李磊"

      var sex:String="男"

}

// 调用了Person自动生成的默认指定构造器(无参数)

var per = Person()

```

结果成功运行。在生成了per实例时,调用了自动生成的默认指定构造器,虽说是无参数,但是Person类在定义时,直接就给name和sex赋值了,所以这个per实例是成功被创建了。这里有一个不得不强调的一点,Swift的指定构造器本质是,确保本类的成员变量一定要被赋值,不是说一定要通过指定构造器来赋值。这个从上面改动的例子中可以看出(默认构造器并没有给成员变量赋值)。

       当某个类有父类时,在其指定构造器中必须调用父类的指定构造器,且在调用父类的指定构造器前,必须得确保这个类的成员变量必须得有值。为证明这些,再定义一个Man类继承自Person类

```

class Man:Person {

       var education:String="本科"

       // age此处并没有被赋值

       var age:Int

       init(name:String, sex:String, age:Int) {

            // 在调用父类的指定构造器之前,先给成员变量age赋值

            self.age=age

            // 调用父类的指定构造器

            super.init(nameStr: name, sexStr: sex)

        }

}

```

如果将上面的例子改成,在指定构造器中先调用父类的指定构造器,而后给成员变量age赋值,像下面一样

```

class Man:Person {

       var education:String="本科"

       // age此处并没有被赋值

       var age:Int

       init(name:String, sex:String, age:Int) {

              // 先调用父类的指定构造器

             super.init(nameStr: name, sexStr: sex)

              // 再给成员变量age赋值

              self.age=age

        }

}

```

结果Xcode报错。

因为age在定义的位置并没有被赋值,所以在调用父类的指定构造器时age无值。对此强调一点:指定构造器在调用父类的构造器前,一定要确保子类引入的成员变量要有值。

      便利构造器

      由convenience关键字修饰,是横向代理。横向代理的意思是,convenience构造器中必须调用同一个类中的其他一个构造器,这个构造器是指定构造器或者便利构造器都行,但是,如果是便利构造器的话,convenience构造器通过调用链(代理链)最终都得调用一个designated构造器。举个例子,将Person和Man类稍微改一下:

```

     class Person {

            var name:String

            var sex:String

            init(name:String) {

                self.name= name

                self.sex="男"

            }

            //指定构造器可以有多个,但是至少有一个

           init(nameStr:String, sexStr:String) {

                self.name= nameStr

                self.sex= sexStr

            }

           //定义便利构造器(使用convenience修饰)

          convenience init(nameString:String, sexString:String) {

                  //这里的便利构造器必须调用同类中的指定构造器,因为Person是基类,便利构造器无法沿着构造器的调用链调用到父类指定构造器,因为基类是没有父类的,Swift不是OC,OC中NSObject是所有对象的基类,而Swift是没有这种“终极”基类的。

                  self.init(nameStr: nameString, sexStr: sexString)

          }

          convenience init(speakWord:String) {

                  self.init(nameStr:"人类", sexStr:"")

                  print("Person--\(speakWord)")

          }

    }


class Man:Person{

       var education:String="本科"

       var age:Int= 10

       override init(name:String) {

             //子类的指定构造器中必须调用父类的指定构造器

             super.init(name: name)

       }

       override init(nameStr:String, sexStr:String) {

             super.init(nameStr: nameStr, sexStr: sexStr)

       }

       init(name:String, sex:String, age:Int) {

            self.age= 20

            super.init(nameStr: name, sexStr: sex)

        }

       //定义指定构造器与父类的便利构造器一样,这里不算重写

      convenience init(showStr:String, age:Int) {

             //这里调用的是从父类继承来的便利构造器

             self.init(speakWord:"hello!")

             self.age= 20

             print("Man---\(showStr)")

       }

}

```

在改过后的Man类中,就不得不提构造器的继承。之前说过构造器默认是不继承,但是在有些情况下,会继承。

1.子类没有定义任何的指定构造器, 那么就会自动从父类那里继承所有的指定构造器

2.如果子类中提供了所有父类指定构造器,不管是通过规则1(没有定义任何指定构造器)继承来的,还是自定义实现的,它将继承所有父类的便利构造器

在改后的Man类中,将Person类中的指定构造器都overrider了,满足第二种情况,所以父类的便利构造器都被继承了。对于上面的规则1,个人觉得其实还可以改的更通俗点儿,只要是子类没有定义指定构造器,子类会从父类那里继承所有的构造器(包括便利构造器),有兴趣的可以试下将Man类其他的构造器都删掉,只保留便利构造器,在编写便利构造器时,会发现Person类的所有构造方法都已被继承。还有一点可以看出,在Man类的便利构造器中,调用的是从父类继承来的便利构造器( 这一句代码:self.init(speakWord:"hello!") ),在该便利构造器中又调用了“init(nameStr:String, sexStr:String)”这个指定构造器,所以调用便利构造器,最终都会沿着调用链调用到一个指定构造器。

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

推荐阅读更多精彩内容

  • 20- 枚举,枚举原始值,枚举相关值,switch提取枚举关联值 Swift枚举: Swift中的枚举比OC中的枚...
    iOS_恒仔阅读 2,235评论 1 6
  • 本章将会介绍 存储属性的初始赋值自定义构造过程默认构造器值类型的构造器代理类的继承和构造过程可失败构造器必要构造器...
    寒桥阅读 766评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 十天前才去看过大舅妈,不曾想昨天她竟然走了。差不多八月二十号,大舅去庆伟哥家帮他看孩子去了,只有舅妈在家。见到我们...
    紫燕风前舞阅读 675评论 0 0
  • 1.form表单有什么作用?有哪些常用的input 标签,分别有什么作用? 作用是:收集填写的信息,提交给网站的后...
    饥人谷_js_chen阅读 177评论 0 0