I have seen code like this that XCode created from objective-c initializers:
init!(logMsg: String!, level logLevel: DDLogLevel, flag logFlag: DDLogFlag, context logContext: Int32, file: UnsafePointer<Int8>, function: UnsafePointer<Int8>, line: Int32, tag: AnyObject!, options optionsMask: DDLogMessageOptions)
init!(logMsg: String!, level logLevel: DDLogLevel, flag logFlag: DDLogFlag, context logContext: Int32, file: UnsafePointer<Int8>, function: UnsafePointer<Int8>, line: Int32, tag: AnyObject!, options optionsMask: DDLogMessageOptions, timestamp aTimestamp: NSDate!)
The original code is:
- (instancetype)initWithLogMsg:(NSString *)logMsg
level:(DDLogLevel)logLevel
flag:(DDLogFlag)logFlag
context:(int)logContext
file:(const char *)file
function:(const char *)function
line:(int)line
tag:(id)tag
options:(DDLogMessageOptions)optionsMask;
- (instancetype)initWithLogMsg:(NSString *)logMsg
level:(DDLogLevel)logLevel
flag:(DDLogFlag)logFlag
context:(int)logContext
file:(const char *)file
function:(const char *)function
line:(int)line
tag:(id)tag
options:(DDLogMessageOptions)optionsMask
timestamp:(NSDate *)aTimestamp;
What does the exclamation mark mean after the init keyword?
The bang or exclamation mark hints at potential danger. If you use an exclamation mark in Swift, you are about to perform an operation that can backfire. You are about to perform a dangerous operation and are doing so at your own risk. That is the meaning of the exclamation mark in Swift.
Swift uses exclamation marks to signal both force unwrapping of optionals and explicitly unwrapped optionals.
The exclamation mark (!), known informally as a bang or a shriek, is used at the end of a sentence or a short phrase which expresses very strong feeling. Here are some examples: What a lovely view you have here! That's fantastic!
An initializer is a special type of function that is used to create an object of a class or struct. In Swift, we use the init() method to create an initializer. For example, class Wall { ... // create an initializer init() { // perform initialization ... } }
The currently accepted answer gives the what, but not the why. I think in this case, understanding why is especially important.
To answer your question directly, it's an initializer that returns an implicitly-unwrapped optional.
Using init?
to indicate that initialization can fail is an effective way to handle errors. It returns an "optional" (such as Type?
), implying that either a value was initialized, or nothing could be initialized and its contents are nil
instead. But when would init!
, which returns an implicitly-unwrapped optional, be useful?
Implicitly-unwrapped optionals indicate that you can be confident that the value you're currently working with is not nil without having to check it, but that it may have been nil at some point in its lifetime. This is in direct contrast to non-optional types, which can never be nil. Since you're working with a value from the very beginning of its lifetime when you obtain it from an initializer, there aren't many use cases for init!
.
It likely exists primarily to help out with the Objective-C framework transitions to avoid having to manually check every single automatically-converted initializer. "This thing might be nil but probably isn't" is how Objective-C works by default. In your case, there's no way for Xcode to know whether or not those methods return an initialized value 100% of the time. It's quite an effort to go through every single framework and figure out whether an initialize should return a Type
or Type?
, so Type!
is a sensible default in the meantime. As proof, Xcode is smart enough to convert initializers containing (NSError **)
to init?
.
One other use case is delegating to a failable initializer with one that you know will never cause the failure condition. But other than that, writing init!
in your own Swift code should probably be avoided when possible (and even that case is still pretty iffy).
Sources:
It is failable initializer, introduced in Swift 1.1 (with Xcode 6.1)
From Apple Developer:
The init! Failable Initializer
You typically define a failable initializer that creates an optional instance of the appropriate type by placing a question mark after the
init
keyword (init?
). Alternatively, you can define a failable initializer that creates an implicitly unwrapped optional instance of the appropriate type. Do this by placing an exclamation mark after theinit
keyword (init!
) instead of a question mark.You can delegate from
init?
toinit!
and vice versa, and you can overrideinit?
withinit!
and vice versa. You can also delegate frominit
toinit!
, although doing so will trigger an assertion if theinit!
initializer causes initialization to fail.
(emphasis mine)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With