Подтвердить что ты не робот

Что означает восклицательный знак для быстрого инициализатора?

Я видел такой код, что 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?

4b9b3361

Ответ 1

Это неудачный инициализатор, введенный в Swift 1.1 (с Xcode 6.1)

Из Разработчик Apple:

Запуск! Неудачный инициализатор

Обычно вы определяете неудачный инициализатор, который создает необязательный экземпляр соответствующего типа, разместив вопросительный знак после init ключевое слово (init?). Кроме того, вы можете определить инициализатор, который создает неявно развернутый необязательный экземплярсоответствующий тип. Сделайте это, поставив восклицательный знак после init ключевое слово (init!) вместо вопросительного знака.

Вы можете делегировать от init? до init! и наоборот, и вы можете переопределить init? с помощью init! и наоборот. Вы также можете делегировать init до init!, хотя это приведет к утверждению, если init! инициализатор приводит к сбою инициализации.

(акцент мой)

Ответ 2

В настоящее время принятый ответ дает то, что, но не почему. Я думаю, в этом случае понимание того, что особенно важно.

Чтобы ответить на ваш вопрос напрямую, это инициализатор, который возвращает неявно-развернутый вариант.

Используя init?, чтобы указать, что инициализация может быть неудачной, является эффективным способом обработки ошибок. Он возвращает "необязательный" (например, Type?), подразумевая, что либо инициализировано значение, либо ничего не может быть инициализировано, а его содержимое nil. Но когда init!, который возвращает неявно-развернутый необязательный, полезно?

Неявно разворачиваемые опционы указывают, что вы можете быть уверены, что значение, с которым вы работаете в настоящее время, не равно нулю, не проверяя его, но возможно, что оно было нулевым в какой-то момент его жизни. Это прямо контрастирует с необязательными типами, которые никогда не могут быть равны нулю. Поскольку вы работаете со значением с самого начала его жизни, когда вы получаете его из инициализатора, для init! не так много вариантов использования.

Вероятно, он существует, прежде всего, чтобы помочь с переходами фрейма Objective-C, чтобы избежать необходимости вручную проверять каждый инициализатор с автоматическим преобразованием. "Это может быть ноль, но, вероятно, нет", как работает Objective-C по умолчанию. В вашем случае для Xcode нет способа узнать, возвращают ли эти методы инициализированное значение в 100% времени. Это достаточно усилий, чтобы пройти через каждую единую структуру и выяснить, должен ли инициализировать return Type или Type?, поэтому Type! является разумным дефолтом. В качестве доказательства Xcode достаточно умен, чтобы конвертировать инициализаторы, содержащие (NSError **) в init?.

Другим вариантом использования является делегирование отказавшего инициализатора тем, который, как вы знаете, никогда не вызовет условие сбоя. Но кроме этого, писать init! в свой собственный код Swift следует, по возможности, избегать (и даже этот случай все еще довольно неплохо).

Источники:

Ответ 3

Они называются "Необоснованно отключенные опции" [1]. Тип obj-c для logMsg (например) - это NSString *, который может быть равен nil. Его можно использовать как необязательный - String?, и в этом случае вы бы явно разворачивали его, чтобы получить значение. Строка! даст вам значение напрямую, поэтому это предполагает, что logMsg не будет равен нулю.

Эти типы опций определяются как неявно развернутые опциональные. Вы пишете неявно разворачиваемую опцию, помещая восклицательный знак (String!), А не знак вопроса (String?) После того типа, который вы хотите сделать необязательным.

Неявно разворачиваемые необязательные варианты полезны, когда подтверждается, что значение optionals существует сразу после того, как опционально определено первым и, безусловно, может быть предположительно существовать в каждой точке после этого.

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