由于Swift支持方法和初始化程序重载,因此可以将多个init放在一起,并使用任何您认为方便的:
class Person {
    var name:String

    init(name: String) {
        self.name = name
    }

    init() {
        self.name = "John"
    }
}

那么为什么便利关键字也存在呢?什么使以下更好?

class Person {
    var name:String

    init(name: String) {
        self.name = name
    }

    convenience init() {
        self.init(name: "John")
    }
}
现有的答案只讲一半的便利故事。另一半的故事,没有一个现有的答案覆盖,回答了问题Desmond发表在评论:

Why would Swift force me to put convenience in front of my initializer just because I need to call self.init from it?`

我在this answer年轻微触及它,其中我详细地覆盖了Swift的初始化规则,但主要关注的是所需的词。但是,这个答案仍然涉及与这个问题和这个答案相关的东西。我们必须了解Swift初始化程序继承的工作原理。

因为Swift不允许未初始化的变量,所以不能保证从你继承的类继承所有(或任何)初始化器。如果我们子类化并添加任何未初始化的实例变量到我们的子类,我们停止继承初始化。直到我们添加我们自己的初始化器,编译器将对我们喊。

要清楚,未初始化的实例变量是没有给出默认值的任何实例变量(请记住,可选项和隐含地解开的可选项自动采用默认值nil)。

所以在这种情况下:

class Foo {
    var a: Int
}

a是未初始化的实例变量。这不会编译,除非我们给一个默认值:

class Foo {
    var a: Int = 0
}

或在初始化方法中初始化a:

class Foo {
    var a: Int

    init(a: Int) {
        self.a = a
    }
}

现在,让我们看看如果我们继承Foo会发生什么,我们呢?

class Bar: Foo {
    var b: Int

    init(a: Int,b: Int) {
        self.b = b
        super.init(a: a)
    }
}

对?我们添加了一个变量,我们添加了一个初始化器来将值设置为b,以便编译。根据你来自哪种语言,你可能期望Bar继承了Foo的初始化器init(a:Int)。但它不。怎么可能呢? Foo的init(a:Int)如何知道如何为Bar添加的b变量赋值?它不。因此,我们无法使用无法初始化所有值的初始化器初始化Bar实例。

这与方便有什么关系?

好吧,让我们来看看the rules on initializer inheritance:

Rule 1

If your subclass doesn’t define any designated initializers,it automatically inherits all of its superclass designated initializers.

Rule 2

If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1,or by providing a custom implementation as part of its deFinition—then it automatically inherits all of the superclass convenience initializers.

注意规则2,其中提到了便利初始化。

所以方便关键字做的是告诉我们哪些初始化器可以被添加没有默认值的实例变量的子类继承。

让我们看一下这个例子Base类:

class Base {
    let a: Int
    let b: Int

    init(a: Int,b: Int) {
        self.a = a
        self.b = b
    }

    convenience init() {
        self.init(a: 0,b: 0)
    }

    convenience init(a: Int) {
        self.init(a: a,b: 0)
    }

    convenience init(b: Int) {
        self.init(a: 0,b: b)
    }
}

注意,我们在这里有三个方便初始化器。这意味着我们有三个可以继承的初始化器。我们有一个指定的初始化器(指定的初始化器只是不是方便初始化器的任何初始化器)。

我们可以通过四种不同的方式实例化基类的实例:

所以,让我们创建一个子类。

class NonInheritor: Base {
    let c: Int

    init(a: Int,b: Int,c: Int) {
        self.c = c
        super.init(a: a,b: b)
    }
}

我们继承自Base。我们添加了我们自己的实例变量,我们没有给它一个默认值,所以我们必须添加我们自己的初始化。我们添加了一个init(a:Int,b:Int,c:Int),但它不匹配Base类的指定初始化器的签名:init(a:Int,b:Int)。这意味着,我们不会从Base继承任何初始化:

所以,如果我们继承Base,会发生什么,但我们继续和实现一个初始化器匹配指定的初始化器从Base?

class Inheritor: Base {
    let c: Int

    init(a: Int,b: b)
    }

    convenience override init(a: Int,b: Int) {
        self.init(a: a,b: b,c: 0)
    }
}

现在,除了我们在这个类中直接实现的两个初始化器之外,因为我们实现了一个匹配Base类的指定初始化器的初始化器,所以我们继承了所有Base类的方便初始化器:

具有匹配签名的初始化器被标记为方便的事实在这里没有差别。它只意味着Inheritor只有一个指定的初始化器。因此,如果我们从Inheritor继承,我们只需要实现一个指定的初始化器,然后我们继承Inheritor的方便初始化器,这反过来意味着我们实现了所有的Base的指定的初始化器,并且可以继承它的方便初始化器。

为什么在Swift中甚至需要便利关键字?的更多相关文章

  1. three.js模拟实现太阳系行星体系功能

    这篇文章主要介绍了three.js模拟实现太阳系行星体系功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

  2. HTML5页面无缝闪开的问题及解决方案

    这篇文章主要介绍了HTML5页面无缝闪开方案,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. 使用xib创建自定义视图

    但是,您必须接受您的XIB将包含根视图或其他内容,这些视图将作为子视图添加到放入Placement的类的实例中.这样,你应该有类似的东西:XIB与您的自定义视图内容:添加XIB的位置:由于添加到展示位置的视图实例与XIB中的文件所有者相同,因此您可以在XIB和Placement中设置出口和操作.只是不要忘记你的XIB中的根视图不是UIKit将创建放置到Placement的实例.为方便起见,请在下面找到我的代码,该代码是基类,以便于创建此类视图:

  4. ios – 无法识别的选择器发送到实例NSTimer Swift

    解决方法让updateTime成为一个类方法.如果它是在一个纯粹的Swift类中,你需要在@objc前面说明该方法的声明,如:

  5. ios – 为什么,将nil作为参数从Objc C发送到swift类初始化器,用新对象替换nil参数

    除非属性本身被声明为nonnull:

  6. ios – 在Swift中对MKCircle进行子类化

    我想通过添加另一个String属性来继承MKCircle,我们称之为“代码”.这个属性不是可选的和常量的,所以我必须从初始化器设置它,对吧?有没有办法定义一个单一的便利初始化器,在这种情况下需要3个参数?本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  7. ios – 类型推断(自动类型检测)如何在swift中工作?

    LLVM如何检测变量是一个字符串?

  8. ios – Swift可选项:语言问题,还是做错了什么?

    应该有可选的类型;type是但是,如果我这样做,它的工作原理:它似乎是基本的替代,但我可能会遗漏一些语言的细微差别.谁能对此有所了解?之后就像暧昧一样,更多,这是我的解决方案:这适用于所有非对象Swift对象,包括Swift字符串,数字等.感谢Viktor提醒我String不是Swift中的对象.如果您知道值的类型,您可以替换任何?使用适当的可选类型,如String?

  9. ios – 覆盖Swift中的超类委托

    我正在开发一个包含两个UIViews的Swift(v1.2)项目.MyView和MyViewSubclass.MyView有一个委托,我想在MyViewSubclass中覆盖它作为一个子协议,类似于UITableViews有一个UITableViewDelegate,它也符合超级uiscrollviewdelegate.我的第一个想法是覆盖超类属性,但这会导致编译器错误,因为子类不能覆盖具有不同类

  10. ios – AVAudioPlayer不再使用Swift 2.0/Xcode 7 beta

    对于我的iPhone应用程序中的vartestAudio声明,我在这里收到错误“调用可以抛出,但错误不能从属性初始化程序中抛出”当我转到Xcode7测试版时,就发生了这种情况.如何在Swift2.0中使用此音频剪辑?

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部