Как вы разворачиваете опционы Swift?
Как правильно развернуть как обычные, так и неявные опции?
Кажется, в этой теме есть путаница, и я просто хотел бы получить справку обо всех способах и их полезности.
В настоящее время существует два способа создания опций:
var optionalString: String?
var implicitOptionalString: String!
Каковы все способы развернуть оба? Кроме того, в чем разница между использованием !
а также ?
во время распаковки?
8 ответов
Есть много сходств и просто несколько различий.
(Обычный) Опционально
Декларация:
var opt: Type?
Небезопасная распаковка:
let x = opt!.property // error if opt is nil
Безопасно проверяя наличие:
if opt != nil { ... someFunc(opt!) ... } // no error
Безопасное распаковывание через привязку:
if let x = opt { ... someFunc(x) ... } // no error
Безопасное сцепление:
var x = opt?.property // x is also Optional, by extension
Безопасное объединение нулевых значений:
var x = opt ?? nonOpt
Неявно развернутые необязательные
Декларация:
var opt: Type!
Небезопасное развертывание (неявное):
let x = opt.property // error if opt is nil
Небезопасная распаковка через назначение:
let nonOpt: Type = opt // error if opt is nil
Небезопасная распаковка через передачу параметров:
func someFunc(nonOpt: Type) ... someFunc(opt) // error if opt is nil
Безопасно проверяя наличие:
if opt != nil { ... someFunc(opt) ... } // no error
Безопасное сцепление:
var x = opt?.property // x is also Optional, by extension
Безопасное объединение нулевых значений:
var x = opt ?? nonOpt
Начиная с бета-версии 5 у нас также есть новый оператор объединения (??):
var a : Int?
let b : Int = a ?? 0
Если необязательный параметр!= Nil, он разворачивается, иначе используется значение справа от оператора.
Я создал подход, чтобы развернуть необязательное значение:
// MARK: - Modules
import Foundation
import UIKit
import CoreData
// MARK: - PROTOCOL
protocol OptionalType { init() }
// MARK: - EXTENSIONS
extension String: OptionalType {}
extension Int: OptionalType {}
extension Double: OptionalType {}
extension Bool: OptionalType {}
extension Float: OptionalType {}
extension CGFloat: OptionalType {}
extension CGRect: OptionalType {}
extension UIImage: OptionalType {}
extension IndexPath: OptionalType {}
extension Date: OptionalType {}
extension UIFont: OptionalType {}
extension UIColor: OptionalType {}
extension UIViewController: OptionalType {}
extension UIView: OptionalType {}
extension NSMutableDictionary: OptionalType {}
extension NSMutableArray: OptionalType {}
extension NSMutableSet: OptionalType {}
extension NSEntityDescription: OptionalType {}
extension Int64: OptionalType {}
extension CGPoint: OptionalType {}
extension Data: OptionalType {}
extension NSManagedObjectContext: OptionalType {}
prefix operator ?*
//unwrapping values
prefix func ?*<T: OptionalType>( value: T?) -> T {
guard let validValue = value else { return T() }
return validValue
}
Вы также можете добавить свой собственный тип данных.
Использование:-
var myString = ?*str
Надеюсь, поможет:)
Необязательный тип означает, что переменная может быть nil.
Пример:
var myString: Int? = 55
myString = nil
Знак вопроса указывает, что он может иметь нулевое значение.
Но если вы заявите, как это:
var myString : Int = 55
myString = nil
Это покажет ошибку.
Теперь, чтобы получить значение, вам нужно развернуть его:
print(myString!)
Но если вы хотите, чтобы развернуть автоматически:
var myString: Int! = 55
Затем:
print(myString)
Не нужно разворачивать. Надеюсь, это поможет.
Безопасное развертывание опций в Swift 5.7 ⛑
Различные техники (в порядке предпочтения)
Используйте правильный инструмент для работы:
- Необязательная цепочка
- Операторы объединения Nil
В Swift есть много способов безопасно развернуть необязательные значения. Мои причины для заказа техники в моих предпочтениях выше:
- Мы должны разворачивать опции только в том случае, если нам это действительно нужно. В этом случае нам не нужно разворачивать его и можно использовать дополнительную цепочку. например
let value = optional?.value
- Защитные операторы полезны для раннего выхода из потока, когда есть предварительное условие. Во многих случаях это самое чистое решение за счет снижения уровня вложенности.
- может быть более удобочитаемым для последовательной логики. В некоторых случаях более удобочитаем, чем s, когда мы не хотим выходить из функции, а продолжаем использовать дополнительную логику за пределами блока развертывания. является гибким и может также использоваться с аналогичным синтаксисом, как операторы.
- Мы можем использовать несколько защитных операторов, чтобы развернуть несколько необязательных параметров перед их использованием, или даже использовать
,
,&&
или||
для проверки нескольких условных выражений в одном файле . - Операторы объединения Nil хорошо работают, чтобы аккуратно развернуть необязательные параметры со значением по умолчанию:
??
. Однако не злоупотребляйте ими, потому что с помощью часто проще выйти раньше. - Я описал улучшенный синтаксис для и
guard let
(намного чище в Swift 5.7). - Принудительная развертка или IUO (неявные необработанные опции) могут привести к сбоям во время выполнения. Они обозначены значком
!
и являются анти-шаблоном в iOS, если только они не являются частью набора тестов, потому что они могут привести к сбою, если необязательныйnil
. В этом случае мы не используем улучшенную систему типов Swift по сравнению с Objective-C. В тестах мы не заботимся о чистоте кода, потому что тесты не будут работать в продакшене, а их назначение скрыто.
Новый синтаксис дляif let
иguard
var x: EnumExample?
if let x {
print(x.rawValue) // No longer optional
}
// We can still explicitly name the `if let` value if we want.
if let value = x {
print(value.rawValue)
}
guard let x else {
return
}
print(x.rawValue) // No longer optional
guard let value = x else {
return
}
print(value.rawValue)
print(x?.rawValue ?? 0) // Unwrap with nil coalescing
ПРИМЕЧАНИЕ. Я также нахожу опциональную цепочку чистой альтернативой разворачиванию опционов и использованию
x != nil
достаточно для случаев, когда нам нужно только проверить существование. Однако это выходит за рамки вопроса о разворачивании опций.
There is only seven ways to unwrap an optional in Swift
var x : String? = "Test"
1,Forced unwrapping — unsafe.
let a:String = x!
2,Implicitly unwrapped variable declaration — unsafe in many cases.
var a = x!
3,Optional binding — safe.
if let a = x {
print("x was successfully unwrapped and is = \(a)")
}
4,Optional chaining — safe.
let a = x?.count
5,Nil coalescing operator — safe.
let a = x ?? ""
6,Guard statement — safe.
guard let a = x else {
return
}
7,Optional pattern — safe.
if case let a? = x {
print(a)
}
Вы также можете создавать расширения для определенного типа и безопасно разворачивать их со значением по умолчанию. Для того же я сделал следующее:
extension Optional where Wrapped == String {
func unwrapSafely() -> String {
if let value = self {
return value
}
return ""
}
}
Пример кода безопасного развертывания с использованием привязки:
let accountNumber = account.accountNumber //optional
let accountBsb = account.branchCode //optional
var accountDetails: String = "" //non-optional
if let bsbString = account.branchCode, let accString = account.accountNumber {
accountDetails = "\(bsbString) \(accString)" //non-optional
}