一个NSObject子类的无参数可失败初始化器

13
我想为NSObject子类提供可失败的初始化程序,以进行无参数的初始化。我的总体目标是,在低于8.0版本的操作系统上初始化此类时返回nil。
下面是我的尝试:
class MyObject: NSObject {
    override init?() {
        super.init()
        if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 {
            return nil
        }

    }
}

然而,这段代码导致以下编译器错误。

Failable initializer 'init()' cannot override a non-failable initializer

在子类中是否可以重写init()方法并提供可失败的实现?或者有更好的方法来实现这个目标吗?

3个回答

6

考虑到:

你可以用非可失败初始化器覆盖可失败初始化器,但反过来不行。

而且

可失败初始化器也可以委托给非可失败初始化器。如果您需要为原本不会失败的初始化过程添加潜在的失败状态,则使用此方法。

(摘自可失败初始化器)

并且考虑到 NSObject 没有一个无参的可失败初始化器,那么不能用可失败初始化器覆盖非可失败初始化器。

我唯一能想到的选择是创建一个带有虚拟参数的初始化器,例如:

class MyObject: NSObject {
    init?(_ ignore: Bool) {
        super.init()
        if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 {
            return nil
        }
    }
}

然后将其用作:

var myObj = MyObject(true)

或者

var myObj = MyObject(false)

更有趣的是,给虚拟参数分配一个默认值似乎能够很好地完成任务:
class MyObject: NSObject {
    init?(_ ignore: Bool = false) {
        super.init()
        if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 {
            return nil
        }
    }
}

var myObj = MyObject()

感谢您对我的问题提出的创造性解决方案。然而,经过更深入的思考,我认为工厂方法(例如@Paulw11的建议)可能是更清晰的解决方案。 - Glen T
2
那个带有默认值的虚拟参数解决方案既邪恶又聪明。 - Rob Keniger

5

由于你正在子类化NSObject,因此你不能拥有一个失败的无参数的初始化程序,因为NSObject的无参数初始化程序不是可失败的。

你可以创建一个类工厂方法,根据iOS版本返回实例或nil。


0
如果你不想传递一个“虚拟”的参数,你可以传递一个inout错误。这样,你就可以避免用虚拟参数污染代码,并且更多地了解为什么初始化失败(如果有必要的话)。
final class FailableFoo: NSObject {
    let foo: String

    enum FailableFooInitializationError: LocalizedError {
        case somethingWentWrong
    }

    required init?(error: inout Error?) {
        foo = "Foo"
        let somethingWentWrong = true
        if somethingWentWrong {
            error = FailableFooInitializationError.somethingWentWrong
            return nil
        } else {
            super.init()
        }
    }
}

final class Bar: NSObject {
    let foo: FailibleFoo?

    override init() {
        var fooInitializationError: Error? = nil
        foo = FailableFoo(error: &fooInitializationError)
        if let fooInitializationError = fooInitializationError {
            // handle init error
        }
        super.init()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接