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

时间:2014-10-18 13:57:25

标签: objective-c swift

我见过这样的代码,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!)

原始代码是:

- (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;

init 关键字后感叹号的含义是什么?

3 个答案:

答案 0 :(得分:17)

目前接受的答案给出了什么,但不是原因。我想在这种情况下,理解为什么特别重要。

要直接回答您的问题,它是一个返回implicitly-unwrapped optional的初始值设定项。

使用init?表示初始化可能失败是处理错误的有效方法。它返回一个&#34;可选&#34; (例如Type?),暗示值已初始化,或者没有任何内容可以初始化,其内容为nil。但是什么时候init!会返回一个隐式解包的可选项呢?

隐式展开的选项表示您可以确信您当前正在使用的值不是零,而不必检查它,但它在其生命周期的某个时刻可能是零。这与非可选类型形成鲜明对比,后者永远不会是零。由于您从初始化程序获取值时从一生中开始使用值,因此init!没有多少用例。

它可能主要用于帮助Objective-C框架转换,以避免必须手动检查每个自动转换的初始化程序。 &#34;这件事可能是零但可能不是&#34;是Objective-C默认工作的方式。在您的情况下,Xcode无法知道这些方法是否在100%的时间内返回初始化值。通过每个框架并确定初始化是应该返回Type还是Type?是非常努力的,因此Type!在此期间是合理的默认值。作为证据,Xcode 足够智能,可以将包含(NSError **)的初始值设定项转换为init?

另一个用例是委托给一个可用的初始化程序,你知道它永远不会导致失败。但除此之外,在可能的情况下,应该尽可能避免在自己的Swift代码中编写init!(即使这种情况仍然相当不确定)。

来源:

答案 1 :(得分:13)

它是可用的初始化程序,在Swift 1.1中引入(使用Xcode 6.1)

来自Apple Developer

  

初始化! Failable Initializer

     

您通常会定义一个可创建的初始化程序,用于创建可选项   通过在后面放置一个问号来获得适当类型的实例   init关键字(init?)。或者,您可以定义可用的   初始化程序,创建一个隐式解包的可选实例   适当的类型。通过在后面放一个感叹号来做到这一点   init关键字(init!)而不是问号。

     

您可以从init?委托给init!,反之亦然,您可以   使用init?覆盖init!,反之亦然。您也可以委派自己   initinit!,尽管这样做会引发断言   init!初始值设定项导致初始化失败。

(强调我的)

答案 2 :(得分:1)

这些被称为'隐含解开的选项'[1]。 logMsg的obj-c类型(例如)是NSString *,可以是nil。它可以用作可选的 - String ?,在这种情况下,你可以明确地解包它来获取值。串!会直接给你这个值,所以这假设logMsg不会是nil。

  

这些类型的期权被定义为隐式解包的期权。您通过在要使其成为可选的类型之后放置感叹号(String!)而不是问号(String?)来编写隐式展开的可选项。

     

如果在首次定义可选项后立即确认可选项的值存在,并且可以假定在此后的每个点都存在,则隐式解包的选项会很有用。

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