What is the purpose of the init! failable initiali

2019-06-21 20:43发布

The Apple Swift Programming Language guide mentions the existence of the init! initializer, but does not provide any example for it. (Search for init! in this page)

I understand the use of a normal failable initializer declared with init?, but I fail to get the need of this other version. What is it needed for? Can somebody provide an example?

6条回答
何必那么认真
2楼-- · 2019-06-21 20:59

It makes a difference in two situations:

If you write

let x: myclass = myclass(...)

then init? will not compile because init? returns an optional; init! will compile but crash if the init method returns nil.

If you write

let x = myclass(...)

then it will compile in either case, and it will not crash in either case. The difference is that in one case x has type myclass? and in the other case type myclass! with the obvious differences in behaviour.

If you write one of the following two:

let x: myclass? = myclass(...)
let x: myclass! = myclass(...)

then it doesn't matter whether init! or init? was used, because either can be assigned to an optional without crashing.

查看更多
手持菜刀,她持情操
3楼-- · 2019-06-21 21:01

I'm going to take a stab at this even though this question has been around for a while because I think some example source code would be useful for understanding what init! is for (at least it was for me).

An implicitly unwrapped optional provides two things of value:

  1. A convenience for the programmer (so you don't have to keep typing '?' at the end of your optional variables), and
  2. Runtime efficiency because it allows you to test an optional for nil only once, and thereafter (as long as it is non-nil) use its unwrapped (i.e. direct) value.

The important part though is that an implicitly unwrapped optional is still an optional, which means it can be tested for nil.

Now, as to the utility of the init!-failable initializer, we can use it to get the two things I listed above (convenience and runtime efficiency), while still allowing an init function to fail (i.e. to return nil). This can happen, as others have noted, by calling into Objective-C API, but it can also happen directly from code you might choose to write. Here's an example:

class A {
    init!() {
        return nil  // something happens that causes init to fail
    }
}

var a:A! = A()      // variable 'a' *is* an optional, and also nil

if a != nil {       // and we can test it!
    print( "a is not nil" )
} else {
    print( "a is nil, better not use it." )
}

In this example, I gave myself a way to fail the initialization of class A, and yes, could as easily have done it with an init? method, but when I create an object of type A I'll probably only ever need to test that the initialization succeeded or failed once--after all, I either created an A or I didn't--and afterwards if it's not nil I'll just want to use the direct value. So in this case, using the init!-failable initializer turns out to be pretty handy.

查看更多
Explosion°爆炸
4楼-- · 2019-06-21 21:08

The init initializer is the same like the constructor for classes in other languages. It sets initial values and performs some initial Operations (like checking wether a value is to big etc.). Interesting: It also takes Parameters and can be overloaded.

Example:

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin: 273.15)

So when when you call the struct it returns different values depending on your call parameters.

For more info: http://www.informit.com/articles/article.aspx?p=2246797

查看更多
我想做一个坏孩纸
5楼-- · 2019-06-21 21:09

Good question Matteo, I´m looking answer for the same question because init! don´t have sense (if it always init an object and we don´t need optional), but I haven´t found any clear answer.

I think that it´s because Apple haven´t finished his work: "...own Objective-C classes, and classes in frameworks that have not yet been audited, initializers are imported as init! ..."

Perhaps be util for you, the text in "Interacting with Objective-C APIs"(Apple)

  • "In Objective-C, initializers directly return the object they initialize. To inform the caller when initialization has failed, an Objective-C initializer can return nil. In Swift, this pattern is built into the language feature called failable initialization. Many Objective-C initializers in iOS and OS X system frameworks have been audited to indicate whether initialization can fail. These Objective-C initializers are imported as either init(...)—if initialization cannot fail–or init?(...) if initialization can fail. In your own Objective-C classes, and classes in frameworks that have not yet been audited, initializers are imported as init!(...). For example, the NSString(contentsOfFile:) initializer can fail to initialize an NSString object if the file doesn’t exist at the provided path. You can use optional binding to unwrap the result of an failable initializer if initialization is successful."

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html

查看更多
Fickle 薄情
6楼-- · 2019-06-21 21:17

This serves two purposes:

  • When importing Cocoa APIs that Swift doesn't know about. If Swift does not know if an initializer can return nil or not, it annotates it with ! so that the developer knows there might be a nil hiding there, without forcing the dev to test for nil if there's actually no reason to.

  • For the same reasons implicitly-unwrapped optionals are used in other contexts (you may be willing to trade compile-time safety for added convenience in some cases).

查看更多
Rolldiameter
7楼-- · 2019-06-21 21:17

I belive it's absolutely the same use of ! as in optionals. init? will return an optional. init! will return an implicitly unwrapped optional.

Implicitly unwrapped optionals are needed for calling Obj-C APIs where you are not sure whether it can return an optional or not. So you use an implicitly unwrapped optional and it behaves like a non-optional type but it will crash if an optional is returned.

Note that when Swift was introduced most Obj-C frameworks returned only implicitly unwrapped optionals but currently a lot of them return optionals or non-optional types because Apple is going through the code and checks whether they can return an optional or not. init! is needed everywhere where Apple hasn't tagged the initializers correctly yet.

查看更多
登录 后发表回答