Proper way to handle a fail to init

2019-04-22 14:59发布

问题:

I am looking for a proper way to handle a invalid argument during a initialization.

I am unsure how to do it using Swift as the init has't a return type. How can I tell whoever is trying to initialize this class that you are doing something wrong?

init (timeInterval: Int) {
    if timeInterval > 0
        self.timeInterval = timeInterval
    else
        //???? (return false?)
}

Thank you!

回答1:

Use a failable initializer. Such an initializer looks very similar to a regular designated initializer, but has a '?' character right after init and is allowed to return nil. A failable initializer creates an optional value.

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

See Apple's documentation on failable initializers for more detail.



回答2:

In swift, you can't really abort a task half way through execution. There are no exceptions in swift and in general the philosophy is that aborting a task is dangerous and leads to bugs, so it just should't be done.

So, you verify a value like this:

assert(timeInterval > 0)

Which will terminate the program if an invalid value is provided.

You should also change timeInterval to be a UInt so that there will be a compiler error if anybody tries to give a < 0 value or an integer value that could be < 0.

It's probably not the answer you're looking for. But the goal is to check for bad parameters as early as possible, and that means doing it before you create any objects with those parameters. Ideally the check should be done at compile time but that doesn't always work.



回答3:

I think this is the best solution, took it from:How should I handle parameter validation Swift

class NumberLessThanTen {
    var mySmallNumber: Int?
    class func instanceOrNil(number: Int) -> NumberLessThanTen? {
        if number < 10 {
            return NumberLessThanTen(number: number)
        } else {
            return nil
        }
    }
    @required init() {
    }
    init(number: Int) {
        self.mySmallNumber = number
    }
}

let iv = NumberLessThanTen.instanceOrNil(17) // nil
let v = NumberLessThanTen.instanceOrNil(5) // valid instance
let n = v!.mySmallNumber // Some 5


回答4:

In the Swift book by Apple, at the very bottom of this section:https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399

They say:

When to Use Assertions

Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include:

An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. A value is passed to a function, but an invalid value means that the function cannot fulfill its task. An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully.

This sounds exactly like your situation!

Thus your code should look like:

init (timeInterval: Int) {
    assert (timeInterval > 0, "Time Interval Must be a positive integer")

    // Continue your execution normally
}


标签: swift ios8