在Swift中添加失败的可选初始化程序

时间:2016-10-17 13:12:29

标签: swift initialization swift3

我正在尝试将一个方便失败的初始值设定项添加到UIFont作为扩展名。所以UIFont已经有一个失败的初始化程序:

open class UIFont : NSObject, NSCopying {
    ...

    public init?(name fontName: String, size fontSize: CGFloat)
    ...
}

所以我想创建一个方便的初始化器来调用这个,类似于下面的代码:

public convenience init?(name fontName: String, size fontSize: CGFloat, weight fontWeight: String) {
    self.init(name: fontName + "-" + fontWeight, size: fontSize)
}

到目前为止一切顺利,这完美无缺。现在我想添加一些自定义逻辑,例如:

public convenience init?(name fontName: String, size fontSize: CGFloat, weight fontWeight: String) {
    if let font = self.init(name: fontName + "-" + fontWeight, size: fontSize) {
        self = font
    }
    else if let font = self.init(name: fontName, size: fontSize) {
        self = font
    }
    else {
        //
        // Add some failback code
        //
        return nil
    }
}

这就是问题的起点。我想要做的是一个基本的便利API,但我无法设法有条件地初始化字体。在上面的示例中,if let font = self.init行中存在语法错误,并显示:Initializer for conditional binding must have Optional type, not '()'。但是这个初始化程序实际上是可选的,由UIFont类定义(见上文),所以我没有看到问题。我尝试返回字体而不是将其分配给self,但没有任何区别。

所以我的问题是:如何在失败的初始化程序中正确实现条件逻辑?

可能是我在这里做错了,或者这可能只是Swift缺少功能/错误?

1 个答案:

答案 0 :(得分:1)

Swift初始化是该语言中最令人困惑的部分之一,特别是如果您来自Objective-C。简短的回答是:

  

与Objective-C初始值设定项不同,Swift初始值设定项不返回值。

(来自https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html)。

因此,当你写:

public convenience init?(
    name fontName: String, size fontSize: CGFloat, weight fontWeight: String
) {
    let font = self.init(name: fontName + "-" + fontWeight, size: fontSize)

font的类型为Void。是的,我知道,它确实引起了人们的注意,因为它与ObjC的模型不同。在Swift中,您将初始化工作委托给另一个初始化工具,但您并未直接管理该实例。因此,您可以将其称为缺失功能。

简单的解决方法是使用工厂方法而不是初始化方法:

public static func from(
    name fontName: String, size fontSize: CGFloat, weight fontWeight: String
) -> UIFont? {
    if let font = self.init(name: fontName + "-" + fontWeight, size: fontSize) {
        return font
    }
    else if let font = self.init(name: fontName, size: fontSize) {
        return font
    }
    else {
        //
        // Add some failback code
        //
        return nil
    }
}