[IOS]Swift开发之坑(8) - Class Initializer

//转载:http://www.jianshu.com/p/82863c103164

Swift的构造器(Initializer)设计的太复杂,分为指定构造器(Designated Initializers) 和 便利构造器(Convenience Initializers)。指定构造器类似于一般语言的构造器,便利构造器的使用就比较复杂了。
Swift 采用以下三条规则来限制构造器之间的代理调用:
规则 1
指定构造器必须调用其直接父类的的指定构造器。
规则 2
便利构造器必须调用同一类中定义的其它构造器。
规则 3
便利构造器必须最终以调用一个指定构造器结束。
一个更方便记忆的方法是:
• 指定构造器必须总是向上代理
• 便利构造器必须总是横向代理
这些规则可以通过下面图例来说明


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

假设有这样的需求:继承NSWindowController,然后在构造器中做初始化,如下代码

public class  PreferencesWindowController:NSWindowController{
    var name:String?;
    public override init(window: NSWindow?) {
        super.init(window: window);
        name = "Preferences";
    }

}

这样写会报错:

 error: 'required' initializer 'init(coder:)' must be provided by     subclass of 'NSWindowController'

^
AppKit.NSWindowController:4:34: note: 'required' initializer is declared in superclass here
  @objc(initWithCoder:) required init?(coder: NSCoder)

init(coder:)构造器是所谓的必要构造器(Required Initializers) ,当重载了一个指定构造器,就必须重载父类的必要构造器。
修改如下:

public class  PreferencesWindowController:NSWindowController{
    var name:String?;
    public override init(window: NSWindow?) {
        super.init(window: window);
        name = "Preferences";
    }
    required public init?(coder: (NSCoder!))
    {
        super.init(coder: coder)

    }

}

这样编译正确了,但如果按下面的方式调用

 var pwc = PreferencesWindowController(windowNibName:"MyWindowControllerNib");

还是会报错:

error: cannot invoke 'init' with an argument list of type '(windowNibName:     StringLiteralConvertible)'
 var pwc = PreferencesWindowController(windowNibName:"MyWindowControllerNib");
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

需修改如下:

public class  PreferencesWindowController:NSWindowController{
    var name:String?;
    public override init(window: NSWindow?) {
        super.init(window: window);
        name = "Preferences";
    }
    required public init?(coder: (NSCoder!))
    {
        super.init(coder: coder)

    }
     public override init()
    {
        super.init()

    }

}

这其实就是要符合构造器的继承规则2:
如果要使用父类的便利构造器,要么不重载父类的指定构造器,要么就必须全部重载父类的指定构造器。
如果只新建一个便利构造器来利用父类的便利构造器,就不必要重载父类的指定构造器,见如下代码:

public class  PreferencesWindowController:NSWindowController{
    var name:String?;

    public convenience init(name:String){
        self.init(windowNibName:"MASPreferencesWindow");
        self.name = name;
    }

}

var pwc = PreferencesWindowController(name:"Preferences");

Swift 1.1要引入了所谓的可失败(failable initializers) 即构造器可能返回nil,用init?表示:

    class Product {
        let name: String!
        init?(name: String ) {
            if name.isEmpty { return nil }
            self.name = name
        }
    }

实际使用中的一个案例:

public class  PreferencesViewController :NSViewController{

    public override convenience  init() {
        self.init(nibName:"PreferencesView" , bundle: nil );
    }
}

会报错:

error: a non-failable initializer cannot delegate to failable initializer 'init(nibName:bundle:)' written with 'init?'
    self.init(nibName:"PreferencesView" , bundle: nil );

因为init(nibName: bundle:)是个failable initializers,而init()是non-failable initializer,不可失败构造器。不可失败构造器不可代理可失败构造器。下面是一种解决方法,通过init!来转换failable initializers到non-failable initializer。

public class  PreferencesViewController :NSViewController{
    public required  init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    public override init!(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil?, bundle: nibBundleOrNil?)
    }

    public override   convenience init () {
        self.init(nibName:"PreferencesView" , bundle: nil );
    }
}

因为Swift的初始化机制和optional的引入,所以设计了如此繁琐的构造器规则,也许可以在parser阶段不检查,通过compiler阶段检查来简化这个机制。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值