感叹号对于快速初始化器意味着什么?

时间:2021-11-04 22:28:07

I have seen code like this that XCode created from objective-c initializers:

我看到过类似这样的代码,XCode是从objective-c初始化器中创建的:

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?

在init关键字之后的感叹号是什么意思?

3 个解决方案

#1


13  

It is failable initializer, introduced in Swift 1.1 (with Xcode 6.1)

它是可故障初始化器,在Swift 1.1中引入(带有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 the init keyword (init!) instead of a question mark.

通常定义一个可失败的初始化器,通过在init关键字(init?)后面放置一个问号来创建适当类型的可选实例。或者,您可以定义一个可失败的初始化器,该初始化器创建适当类型的隐式未封装的可选实例。在init关键字(init!)后面加上一个感叹号,而不是一个问号。

You can delegate from init? to init! and vice versa, and you can override init? with init! and vice versa. You can also delegate from init to init!, although doing so will trigger an assertion if the init! initializer causes initialization to fail.

可以从init中委托?初始化!反之亦然,你可以重写init?初始化!反之亦然。您还可以从init委托到init!,尽管这样做会在init中触发一个断言!初始化程序导致初始化失败。

(emphasis mine)

(强调我的)

#2


17  

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?

使用初始化?表示初始化可能失败是处理错误的有效方法。它返回一个“可选的”(例如Type?),这意味着要么一个值被初始化,要么什么都不能初始化,它的内容反而是nil。但当会初始化!,哪个返回一个隐含的未包装的可选选项,有用吗?

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!.

隐含的未包装的选项表示,您可以确信当前使用的值不是nil,而不必检查它,但在其生命周期的某个时刻,它可能是nil。这与非可选类型形成了直接的对比,非可选类型永远不会是nil。由于从初始化器获取它的生命周期的初始值,所以初始化的用例并不多!

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?.

它可能主要用于帮助处理Objective-C框架转换,以避免必须手动检查每个自动转换初始化器。“这个东西可能是nil,但很可能不是”,这是Objective-C默认的工作方式。在您的示例中,Xcode无法知道这些方法是否100%地返回初始化值。遍历每个框架并确定初始化应该返回类型还是类型是相当困难的。,所以类型!与此同时,这是一个合理的违约。作为证明,Xcode足够聪明,可以将包含(NSError *)的初始化器转换为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).

另一个用例是委托给一个失败的初始化器,您知道它不会导致故障情况。除此之外,还要写init!在您自己的Swift代码中,可能的情况下应该避免(即使是这种情况也仍然是不确定的)。

Sources:

来源:

  • Xcode release notes on the ongoing optional conformance conversion
  • 关于正在进行的可选一致性转换的Xcode发布说明
  • This post on the Apple Developer Forums
  • 这篇文章发表在苹果开发者论坛上
  • My own thoughts on the matter
  • 我对这件事的看法

#3


1  

These are called 'Implictly Unwrapped Optionals'[1]. The obj-c type for logMsg (for example) is NSString*, which can be nil. It could be used as an optional - String?, in which case you would to explictly unwrap it to get the value. String! will give you the value directly, so this assumes that logMsg won't be nil.

这些被称为“隐含无包选项”[1]。logMsg的object -c类型(例如)是NSString*,它可以是nil。它可以用作可选字符串吗?在这种情况下,你需要明确地打开它以得到它的值。字符串!会直接给你值,所以这假设logMsg不是nil。

These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.

这些选项被定义为隐式展开选项。您可以在您想要使可选的类型后面放置感叹号(String!)而不是问号(String?),从而编写一个隐式的未封装可选。

Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter.

当可选项的值在第一次定义可选项之后被确认为立即存在时,隐式展开可选项是有用的,并且可以肯定地假设可选项在以后的每个点上都存在。

--
1. https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

——1。https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

#1


13  

It is failable initializer, introduced in Swift 1.1 (with Xcode 6.1)

它是可故障初始化器,在Swift 1.1中引入(带有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 the init keyword (init!) instead of a question mark.

通常定义一个可失败的初始化器,通过在init关键字(init?)后面放置一个问号来创建适当类型的可选实例。或者,您可以定义一个可失败的初始化器,该初始化器创建适当类型的隐式未封装的可选实例。在init关键字(init!)后面加上一个感叹号,而不是一个问号。

You can delegate from init? to init! and vice versa, and you can override init? with init! and vice versa. You can also delegate from init to init!, although doing so will trigger an assertion if the init! initializer causes initialization to fail.

可以从init中委托?初始化!反之亦然,你可以重写init?初始化!反之亦然。您还可以从init委托到init!,尽管这样做会在init中触发一个断言!初始化程序导致初始化失败。

(emphasis mine)

(强调我的)

#2


17  

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?

使用初始化?表示初始化可能失败是处理错误的有效方法。它返回一个“可选的”(例如Type?),这意味着要么一个值被初始化,要么什么都不能初始化,它的内容反而是nil。但当会初始化!,哪个返回一个隐含的未包装的可选选项,有用吗?

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!.

隐含的未包装的选项表示,您可以确信当前使用的值不是nil,而不必检查它,但在其生命周期的某个时刻,它可能是nil。这与非可选类型形成了直接的对比,非可选类型永远不会是nil。由于从初始化器获取它的生命周期的初始值,所以初始化的用例并不多!

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?.

它可能主要用于帮助处理Objective-C框架转换,以避免必须手动检查每个自动转换初始化器。“这个东西可能是nil,但很可能不是”,这是Objective-C默认的工作方式。在您的示例中,Xcode无法知道这些方法是否100%地返回初始化值。遍历每个框架并确定初始化应该返回类型还是类型是相当困难的。,所以类型!与此同时,这是一个合理的违约。作为证明,Xcode足够聪明,可以将包含(NSError *)的初始化器转换为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).

另一个用例是委托给一个失败的初始化器,您知道它不会导致故障情况。除此之外,还要写init!在您自己的Swift代码中,可能的情况下应该避免(即使是这种情况也仍然是不确定的)。

Sources:

来源:

  • Xcode release notes on the ongoing optional conformance conversion
  • 关于正在进行的可选一致性转换的Xcode发布说明
  • This post on the Apple Developer Forums
  • 这篇文章发表在苹果开发者论坛上
  • My own thoughts on the matter
  • 我对这件事的看法

#3


1  

These are called 'Implictly Unwrapped Optionals'[1]. The obj-c type for logMsg (for example) is NSString*, which can be nil. It could be used as an optional - String?, in which case you would to explictly unwrap it to get the value. String! will give you the value directly, so this assumes that logMsg won't be nil.

这些被称为“隐含无包选项”[1]。logMsg的object -c类型(例如)是NSString*,它可以是nil。它可以用作可选字符串吗?在这种情况下,你需要明确地打开它以得到它的值。字符串!会直接给你值,所以这假设logMsg不是nil。

These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.

这些选项被定义为隐式展开选项。您可以在您想要使可选的类型后面放置感叹号(String!)而不是问号(String?),从而编写一个隐式的未封装可选。

Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter.

当可选项的值在第一次定义可选项之后被确认为立即存在时,隐式展开可选项是有用的,并且可以肯定地假设可选项在以后的每个点上都存在。

--
1. https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

——1。https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html