Swiftのオプション

モバイル開発の経験(Swiftの使用を含む)にもかかわらず、Swiftのオプションに基づいてをすべきを定期的に知ってましたが、 なぜそうなのか明確に理解できませんでした。 気を散らし、ドキュメントを掘り下げなければなりませんでした-「限界ノート」の数は、憂鬱な周期性で補充されました。 ある時点で、彼らは大衆に達し、私はそれらを単一の包括的なガイドにまとめることにしました。 可能な限り詳細にトピックを開示する試みが行われたため、資料は非常に膨大であることが判明しました。 この記事は、Swiftの初心者開発者とObjective-Cの世界の経験豊富な専門家の両方に役立ちます。Objective-Cの世界では、Objective-Cが新しい何かを見つける可能性がゼロではありません。 そして、それが見つからない場合は、コメントに独自の新しいものを追加し、誰もが利益を得ます。


オプションとは何ですか?


オプションは、変数の値が存在しない状況を処理するための便利なメカニズムです。 値は、使用されている場合にのみ使用されます。


nilのチェックがあるときにオプションが必要なのはなぜですか?


まず、 nil等価性/不等価性チェックは、 null許容型にのみ適用され、プリミティブ型、構造体、および列挙には適用されません。 プリミティブ型の変数に値がないことを示すには、 NSNotFoundなどの特別な値を入力する必要があります。


ご注意

NSNotFoundは、特別な値と見なされる必要があるだけでなく、変数の有効な値のセットに入らないようにするためにも必要です。 NSNotFoundNSIntegerMaxと等しいと見なされるという事実により、状況は複雑になります。 プラットフォーム(32ビット/ 64ビット)によって意味が異なる場合があります。 これは、 NSNotFoundをファイルやアーカイブに直接書き込むことも、 分散オブジェクトで使用することできないことを意味します。


したがって、この変数のユーザーは、特別な値が可能なことを考慮する必要があります。 Swiftでは、プリミティブ型でもオプションのスタイルで使用できます。つまり、値がない可能性があることを明示的に示します。


第二に、コンパイル段階で明示的なオプションがチェックされるため、実行時のエラーの数が減ります。 Swiftのオプション変数は、オプション変数と同じ方法で使用することはできません(暗黙的に取得されたオプションを除き、詳細については暗黙的なアンラッピングを参照してください )。 オプションを強制的に通常の値に変換するか、 if letguard letおよび??などの特別な変換イディオムを使用する必要があります。 。 Swiftのオプションは、検証だけでなく、 理論の オプション型のパラダイム全体を実装します。


第三に、オプションはnilチェックよりも構文的に簡潔です。これは、オプションの呼び出しチェーン、いわゆるOptional Chainingで特に顕著です。


どのように機能しますか?


Swiftのオプションは、 nilまたは特定のタイプのオブジェクトを含むことができる特別なコンテナオブジェクトです。このオブジェクトは、このコンテナが宣言されたときに指定されます。 これらの2つの状態はそれぞれ用語NoneおよびSomeで示されます。 オプション変数の作成中に割り当てられた値が指定されていない場合、デフォルトでnil割り当てられます。


ご注意

ドキュメントでは、明示的な割り当てがない場合のデフォルト値は言及されていませんが、オプションはラップされた値またはnil(valueがない場合)を表す と言われています。 オプション変数が明示的な割り当てなしで宣言された場合(一部は割り当てられなかったものもあります)、論理的にはNoneが暗黙的に割り当てられます-オプションには3番目の「初期化されていない」状態はありません。


タイプ名とトークンの組み合わせでオプションが宣言されています? 。 エントリはInt? -これはコンテナ宣言であり、そのインスタンスには内部nil (状態None Int )またはタイプInt (状態Some Int )の値が含まれる場合があります。 それがInt?変換するときの理由Int? Intでは、 castの代わりにunwrappingという用語を使用します。 オプションの「コンテナ」の本質を強調しています。 Swift nilトークンは、任意のオプションに割り当てることができるNone状態を示します。 これにより、論理的に、オプションではない変数にnil (状態None )を割り当てることができなくなります。


実際、オプションはシステム列挙です:


 public enum Optional<Wrapped> : ExpressibleByNilLiteral { /// The absence of a value. /// /// In code, the absence of a value is typically written using the `nil` /// literal rather than the explicit `.none` enumeration case. case none /// The presence of a value, stored as `Wrapped`. case some(Wrapped) /// Creates an instance that stores the given value. public init(_ some: Wrapped) ... /// Creates an instance initialized with `nil`. /// /// Do not call this initializer directly. It is used by the compiler // when you initialize an `Optional` instance with a `nil` literal. public init(nilLiteral: ()) ... } 

Optional列挙には、 .nonesome(Wrapped) 2つの状態があります。 レコードがWrapped? プリプロセッサ( Swiftの型システム )によって処理され、 Optional<Wrapped>変換されます。 次のエントリは同等です。


 var my_variable: Int? 

 var my_variable: Optional<Int> 

実際、 nilトークンはOptional.none 、つまり 次のエントリは同等です。


 var my_variable: Int? = nil 

 var my_variable: Optional<Int> = Optional.none 

 var my_variable = Optional<Int>.none 

Optional列挙には、2つのコンストラクターがあります。 最初のコンストラクタinit(_ some: Wrapped)は、対応する型の値を入力として受け入れます。 次のエントリは同等です。


 var my_variable = Optional(42) //  .some- Int   

 var my_variable = Optional<Int>(42) //    Int   

 var my_variable = Int?(42) //  Int    

 var my_variable: Int? = 42 //  Int    

 var my_variable = Optional.some(42) //  Int   

 var my_variable = Optional<Int>.some(42) //      

2番目のコンストラクタinit(nilLiteral: ())は、 ExpressibleByNilLiteralプロトコルの実装です


 public protocol ExpressibleByNilLiteral { /// Creates an instance initialized with `nil`. public init(nilLiteral: ()) } 

オプションの変数を状態.noneで初期化します。 このコンストラクターはコンパイラーによって使用されます。 ドキュメントによると、直接呼び出すことは推奨されていません


 var test = Optional<Int>(nilLiteral: ()) //   

空のVoid ()タプルをnil変換することnilいくぶん明白でnilないため、これは論理的です。


代わりにこのコンストラクタを使用してください


 var my_variable: Int? = nil //  var my_variable: Int? = Optional.none 

または明示的な割り当てをまったく使用しない


 var my_variable: Int? 

デフォルトではnilが割り当てられるためです。


Optional<Wrapped>列挙には、unsafelyUnwrappedプロパティも含まれます。このプロパティは、オプションのオプションの.someへの読み取りアクセスを提供.someます。


 public enum Optional<Wrapped> : ExpressibleByNilLiteral { ... /// The wrapped value of this instance, unwrapped without checking whether /// the instance is `nil`. public var unsafelyUnwrapped: Wrapped { get } } 

オプションが.none状態の場合、 .noneにアクセスすると、プログラムが深刻にクラッシュします。


詳細

デバッグモードデバッグビルド-なしでは、ランタイムエラーが発生します。


 _fatal error: unsafelyUnwrapped of nil optional_ 

リリースビルドで最適化されたビルド-Oでは 、ランタイムエラーまたは未定義の動作が発生します。 より安全な操作はForce Unwrapping (またはExplicit Unwrapping!トークンで示される.some.some抽出を.someします!Force Unwrapping.none状態のオプションに適用すると、ランタイムエラーが発生します。


 _fatal error: unexpectedly found nil while unwrapping an Optional value_ 

 let my_variable1 = Int?(42) //  42,  Optional Int let my_value1A = my_variable1! //  42,  Int let my_value1B = my_variable1.unsafelyUnwrapped //  42,  Int let my_variable2 = Int?.none //  nil,  Optional Int let my_value2A = my_variable2! //   //     -Onone,     -O let my_value2B = my_variable2.unsafelyUnwrapped 

使用のイディオム


通常の2状態の列挙を使用することはほとんど意味がありません。 同様のメカニズムを自分で実装することは非常に可能です:対応する値の2つの状態とコンストラクターを使用して列挙型を作成し、 Force Unwrappingの接尾辞演算子を追加し(たとえば、 ここで行われます )、 nilと比較する機能を追加するか、独自のnilとtを作成します.d。 オプションは、その使用が外国ではなく自然であるように、言語自体に直接統合する必要があります。 もちろん、このような統合は「シンタックスシュガー」と見なすことができますが、その上にコードを記述(および読み取り)するための高レベル言語は簡単で快適でした。 Swiftでオプションを使用するには、エラーを減らし、コードをより簡潔にするために、いくつかのイディオムまたは特別な言語構成が必要です。 そのようなイディオムには、 暗黙的なアンラッピングオプションのチェーンNil-Coalescing、およびオプションのバインディングが含まれます。


暗黙的なアンラッピング


Force Unwrappingを安全に使用するは、たとえばif条件でnilを事前に確認する必要があります。


 // getOptionalResult()   nil let my_variable: Int? = getOptionalResult() //  Optional Int if my_variable != nil { // my_value  .some-   getOptionalResult() let my_value = my_variable! } else { //   let my_value = my_variable! } 

プログラムの構造から、変数は技術的にはオプションであることが明らかな場合もありますが、最初の使用時には常に.some状態になっています。 nilはありません。 オプションを非オプションのコンテキストで使用するには(たとえば、オプションの型のパラメーターを使用して関数に渡す)、退屈で面倒な事前チェックでForce Unwrappingを常に使用する必要があります。 これらの場合、暗黙的な取得オプション-Implicitly Unwrapped Optionalを使用できます。 暗黙的な検索オプションは、タイプ名とトークンの組み合わせで宣言されます!


 let my_variable1: Int? = 42 //  Optional Int let my_variable2: Int! = 42 //  Implicitly Unwrapped Optional Int var my_variable3: Int! = 42 //  Implicitly Unwrapped Optional Int ... my_variable3 = nil // -   nil ... func sayHello(times:Int) { for _ in 0...times { print("Hello!") } } sayHello(times: my_variable1!) //     sayHello(times: my_variable1) //   sayHello(times: my_variable2!) // ,       sayHello(times: my_variable2) //   sayHello(times: my_variable3) //   

sayHello(times: my_variable2)への呼び出しでは、 my_variable2からの値42抽出は暗黙的にのみ実行されます。 暗黙的に取得されたオプションを使用すると、コードが読みやすくなります-気を散らす感嘆符はありません(おそらく、読者は最初にチェックせずにForce Unwrappingを使用することを心配するでしょう)。 実際には、エラーの可能性を高めるアンチパターンです。 暗黙的に取得されたオプションは、オプションのコンテキストでオプションが使用されているという事実にコンパイラーに「目を閉じさせる」ことを強制します。 コンパイル時に検出できるエラー( sayHello(times: my_variable1)は実行時にのみ表示されます( sayHello(times: my_variable3)呼び出す)。 明示的なコードは、暗黙的なコードよりも常に優れています。 感嘆符をなくすためだけでなく、このようなコードセキュリティの低下が必要であると想定するのは論理的です。


暗黙的に取得されたオプションを使用selfと、コンストラクターでselfを使用してプロパティを初期化すると同時に、次のことができます。



コンストラクターでselfを使用してプロパティを初期化する良い例は、 ドキュメントに記載されています


 class Country { let name: String var capitalCity: City! init(name: String, capitalName: String) { self.name = name self.capitalCity = City(name: capitalName, country: self) } } class City { let name: String unowned let country: Country init(name: String, country: Country) { self.name = name self.country = country } } var country = Country(name: "Canada", capitalName: "Ottawa") print("\(country.name)'s capital city is called \(country.capitalCity.name)") // Prints "Canada's capital city is called Ottawa" 

この例では、 CountryクラスとCityクラスのインスタンスには、初期化が完了するまでに相互にフレンドリンクが必要です。 各国には首都がなければならず、各首都には国がなければなりません。 これらの接続はオプションではなく、無条件です。 countryオブジェクトを初期化するプロセスでは、 capitalCityプロパティを初期化する必要があります。 capitalCityを初期化するには、 Cityクラスのインスタンスを作成する必要があります。 Cityコンストラクターには、対応するCountryインスタンスがパラメーターとして必要です。 selfへのアクセスが必要です。 問題は、 Countryインスタンスがまだ完全に初期化されていないことです。 selfは使用できません。


このタスクにはエレガントなソリューションがありますcapitalCity 、暗黙的に取得される可変オプションであるcapitalCity宣言されています。 任意の可変オプションと同様に、 capitalCityはデフォルトでnil状態に初期化されます。つまり、 Cityコンストラクターが呼び出されるまでに、 countryオブジェクトのすべてのプロパティはすでに初期化されています。 2段階の初期化の要件が満たされ、 Countryコンストラクターは第2フェーズにありますselfCityコンストラクターに渡すことができます。 capitalCityは暗黙的なオプションです。 追加せずにオプションのコンテキストでアクセスできます!


暗黙的に取得されたオプションを使用することの副作用は、「組み込み」 assertです。何らかの理由でcapitalCitynil状態のままになると、ランタイムエラーとプログラムのクラッシュが発生します。


暗黙的に取得された@IBOutletの正当な使用のもう1つの例は@IBOutlet命令です。その使用のコンテキストは、変数が最初の呼び出し時に.some値を自動的に割り当てられることを意味します。 そうでない場合、実行時エラーが発生します。 Interface Builderの自動コード生成は、暗黙的な@IBOutlet形式で@IBOutletしてプロパティを作成し@IBOutlet 。 この動作が受け入れられない場合、 @IBOutletを持つプロパティを明示的なオプションとして宣言し、常に.none値を明示的に処理.noneます。 原則として、誤って@IBOutlet -propertyが@IBOutletれた場合に長時間のデバッグを行うよりも、すぐに「フォール」を取得することをお@IBOutletます。


オプションの連鎖


オプションのチェーンは、各リンクがオプションを返す連続したチェーン呼び出しのプロセスです。 プロセスは、 nil状態にある最初のオプションで中断されます。この場合、呼び出しチェーン全体の結果もnilます。 チェーン内のすべてのリンクが.some状態にある場合、結果の値は最後の呼び出しの結果ではオプションになります。 チェーンリンクの形成にトークンが使用されています? 、オプションを返す呼び出しの直後に配置されます。 チェーンリンクには、オプションを返す任意の操作を使用できます。ローカル変数へのアクセス(最初のリンクとして)、プロパティとメソッドの呼び出し、インデックスによるアクセス。


オプションのシェーニングは、常に左から右に順番に機能します。 次の.someは前のリンクの値であり、チェーンの結果の値は常にオプションです。 チェーンは、次のルールに従って機能します。



 //    :   —  `country.mainSeaport?`, country.mainSeaport?.nearestVacantPier?.capacity //  ,  `?`     let mainSeaport = country.mainSeaport? //   `nil`    country = Country(name: "Mongolia") let capacity = country.mainSeaport?.mainPier?.capacity //    —      country = Country(name: "Finland") let nearestVacantPier = country.mainSeaport?.nearestVacantPier //    —   ,   capacity //    country = Country(name: "Finland") let capacity = country.mainSeaport?.nearestVacantPier?.capacity 

オプションの呼び出しチェーンとネストされたオプションを区別することが重要です。 ネストされたオプションは.someあるオプションの.someが別のオプション.someある場合に形成されます。


 let valueA = 42 let optionalValueA = Optional(valueA) let doubleOptionalValueA = Optional(optionalValueA) let tripleOptionalValueA = Optional(doubleOptionalValueA) let tripleOptionalValueB: Int??? = 42 //  `?`    let doubleOptionalValueB = tripleOptionalValueB! let optionalValueB = doubleOptionalValueB! let valueB = optionalValueB! print("\(valueA)") // 42 print("\(optionalValueA)") // Optional(42) print("\(doubleOptionalValueA)") // Optional(Optional(42)) print("\(tripleOptionalValueA)") // Optional(Optional(Optional(42))) print("\(tripleOptionalValueB)") // Optional(Optional(Optional(42))) print("\(doubleOptionalValueB)") // Optional(Optional(42)) print("\(optionalValueB)") // Optional(42) print("\(valueB)") // 42 

オプションのシェーニングでは、返されるオプションのネストレベルは増加しません。 それにもかかわらず、これは、リンクの結果の値がいくつかのレベルのネストを持つオプションである場合の状況を除外しません。 このような状況では、チェーンを継続するには登録する必要があります? ネストレベルの数に等しい量:


 let optionalAppDelegate = UIApplication.shared.delegate let doubleOptionalWindow = UIApplication.shared.delegate?.window let optionalFrame = UIApplication.shared.delegate?.window??.frame //  '?' print("\(optionalAppDelegate)") // Optional( ... ) print("\(doubleOptionalWindow)") // Optional(Optional( ... )) print("\(optionalFrame)") // Optional( ... ) 

ご注意

一般的に、トークンを使用してすべてのレベルのネストを「デプロイ」する必要はありません? それらのいくつかは、強制抽出によって置き換えることができます! 、チェーン内の「暗黙的な」リンクの数を減らします。 別の質問は、これが理にかなっているかどうかです。


UIApplication.shared.delegate?.window??.frameチェーンは、実際には4つのリンクで構成されています: UIApplication.shared.delegate? .frameと2つのリンクを1回の呼び出しで結合します。 。 2番目の「二重」リンクは、オプションのネストの2番目のレベルで表されます。


この例の重要な機能は、前の例のdoubleOptionalValueの形成方法とは異なり、double optionalを形成する特別な方法でもあります。 UIApplication.shared.delegate!.windowは、オプションが返されるオプションのプロパティです。 プロパティのオプションとは、プロパティから返されるオプションの.someだけでなく、プロパティ自体が存在しない可能性があることを意味します。 オプションのプロパティは、他のすべてのプロパティと同様に、オプションのプロパティだけでなく、任意のタイプを返すことができます。 この種のオプションは、 optional修飾子を使用して@ objcプロトコルで形成されoptional


 public protocol UIApplicationDelegate : NSObjectProtocol { ... @available(iOS 5.0, * ) optional public var window: UIWindow? { get set } //  optional ... } 

オプションのプロパティとメソッド(それ以外の場合はオプションの要件)を備えたプロトコルでは、オプションの要件ごとおよびプロトコル自体に対して@objc修飾子@objc指定されます。 この要件は、上の例のUIApplicationDelegateプロトコルには適用されません。 Objective-CのシステムライブラリからSwiftに変換されます。 そのようなプロトコルを受け入れるオブジェクトで未実現のオプション要件を呼び出すと、対応するタイプのオプションが.none状態で.noneます。 実装されたオプション要求を呼び出すと、対応するタイプのオプションが.some状態で.someます。 したがって、オプションのプロパティとメソッドは、 オプションのshainingとは対照的に、返されるオプションのネストレベルを増やします。 オプションのメソッドは、プロパティと同様に、オプションで完全に「ラップ」されます。メソッド全体は、戻り値だけでなく.some値に配置されます。


 @objc public protocol myOptionalProtocol { @objc optional var my_variable: Int { get } @objc optional var my_optionalVariableA: Int? { get } //  : //  @objc      Int?, .. Int //    @objc optional var my_optionalVariableB: UIView? { get } @objc optional func my_func() -> Int @objc optional func my_optionalResultfuncA() -> Int? //  : //  @objc      Int?, .. Int //    @objc optional func my_optionalResultfuncB() -> UIView? @objc optional init(value: Int) //  : //  optional    } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, myOptionalProtocol { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { let protocolAdoption = self as myOptionalProtocol // Optional<Int> print("\(type(of: protocolAdoption.my_variable))") // Optional<Optional<UIView>> print("\(type(of: protocolAdoption.my_optionalVariableB))") // Optional<() -> Int> print("\(type(of: protocolAdoption.my_func))") // Optional<Int> print("\(type(of: protocolAdoption.my_func?()))") // Optional<() -> Optional<UIView>> print("\(type(of: protocolAdoption.my_optionalResultfuncB))") // Optional<UIView> print("\(type(of: protocolAdoption.my_optionalResultfuncB?()))") return true } } 

@objc - , , Swift Objective-C:



Force Unwrapping , Force Unwrapping .none .


Nil-Coalescing


Nil-Coalescing .some - , .some , , .none . Nil-Coalescing , if else , , ?


 let optionalText: String? = tryExtractText() //  let textA: String if optionalText != nil { textA = optionalText! } else { textA = "Extraction Error!" } //   ,    let textB = (optionalText != nil) ? optionalText! : "Extraction Error!" //     let textC = optionalText ?? "Extraction Error!" 

.some - . :


 let optionalText: String?? = tryExtractOptionalText() let a = optionalText ?? Optional("Extraction Error!") 

:


 let wayA: Int? = doSomething() let wayB: Int? = doNothing() let defaultWay: Int = ignoreEverything() let whatDo = wayA ?? wayB ?? defaultWay 

Optional Binding


Optional Binding , .some -, , ( ). Optional Binding if , while guard .


Optional Binding , , .


Swift return () . = , == .


, , nil , nil . if , true , nil false :


 var my_optionalVariable: Int? = 42 //  , my_variable ""  .some- my_optionalVariable if let my_variable = my_optionalVariable { print("\(my_variable)") // 42 } my_optionalVariable = nil //  , my_variable   if let my_variable = my_optionalVariable { print("\(my_variable)") } else { print("Optional variable is nil!") // Optional variable is nil! } 

, true , . - nil .some - . true .some - "" ( Optional Binding ).


if true , , false . , , .some -, false ( .none ) . guard :


 let my_optionalVariable: Int? = extractOptionalValue() //   let my_variableA: Int if let value = my_optionalVariable { my_variableA = value } else { return } print(my_variableA + 1) //  guard let my_variableB = my_optionalVariable else { return } print(my_variableB + 1) 

Swift (, ) as . , (, ), as! , as?Force Unwrapping , .. , nil :


 class Shape {} class Circle: Shape {} class Triangle: Shape {} let circle = Circle() let circleShape: Shape = Circle() let triangleShape: Shape = Triangle() circle as Shape //   42 as Float //   circleShape as Circle //   circleShape as! Circle // circle triangleShape as! Circle //   circleShape as? Circle // Optional<Circle> triangleShape as? Circle // nil 

, as? , Optional Binding :


 class Shape {} class Circle: Shape {} class Triangle: Shape {} let circleShape: Shape = Circle() let triangleShape: Shape = Triangle() //  ,   if let circle = circleShape as? Circle { print("Cast success: \(type(of: circle))") // Cast success: (Circle #1) } else { print("Cast failure") } //  ,    if let circle = triangleShape as? Circle { print("Cast success: \(type(of: circle))") } else { print("Cast failure") // Cast failure } 

map flatMap


map flatMap Swift, Optional :


 public enum Optional<Wrapped> : ExpressibleByNilLiteral { ... /// Evaluates the given closure when this `Optional` instance is not `nil`, /// passing the unwrapped value as a parameter. /// /// Use the `map` method with a closure that returns a nonoptional value. public func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? /// Evaluates the given closure when this `Optional` instance is not `nil`, /// passing the unwrapped value as a parameter. /// /// Use the `flatMap` method with a closure that returns an optional value. public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U? ... } 

.some - , . nil , nil . map flatmap -: flatMap nil (), map :


 let my_variable: Int? = 4 let my_squareVariable = my_variable.map { v in return v * v } print("\(my_squareVariable)") // Optional(16) let my_reciprocalVariable: Double? = my_variable.flatMap { v in if v == 0 { return nil } return 1.0 / Double(v) } print("\(my_reciprocalVariable)") // Optional(0.25) 

map flatmap , if guard , , :


 let dateFormatter = DateFormatter() dateFormatter.dateFormat = "dd MMM yyyy" let date: Date? = extractOptionalDate() //  let dateStringA: String if date != nil { dateStringA = dateFormatter.string(from: date!) } else { dateStringA = "Unknown date" } //   ,    let dateStringB = (date == nil ? nil : dateFormatter.string(from: date!)) ?? "Unknown date" // ,     ( map  ) let dateStringC = date.map(dateFormatter.string) ?? "Unknown date" 

, . , .some - , map flatmap :


 //  Optional Binding        func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if let cell = sender as? UITableViewCell, let indexPath = tableView.indexPathForCell(cell) { let item = items[indexPath.row] } } //    3 : // 1)     ; // 2)      flatMap  ; // 3) Optional Binding   flatMap. func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if let indexPath = (sender as? UITableViewCell).flatMap(tableView.indexPathForCell) { let item = items[indexPath.row] } } 


Swift , — nil . try? ( ):


 func someThrowingFunction() throws -> Int { // ... } //  let y: Int? do { y = try someThrowingFunction() } catch { y = nil } //  let x = try? someThrowingFunction() 

x y , , someThrowingFunction() . , try? , as?try! , . , :


 //  ,  loadImage    // photo    (   x  y) let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg") 

Objective-C


Objective-C . nil Objective-C , .. nil . Swift nil .none , nil , Xcode 6.3 Objective-C Swift . Xcode 6.3 Objective-C nullability annotations :


 @interface myObject : NSObject @property (copy, readonly) NSArray * _Nullable myValuesA; @property (copy, readonly) NSString * _Nonnull myStringA; @property (copy, readonly, nullable) NSArray * myValuesB; @property (copy, readonly, nonnull) NSString * myStringB; @end 

nullable ( _Nullable ), nonnull ( _Nonnull ), null_unspecified null_resettable . Nullability -a , . NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END . , Objective-C ( , , nil nonnull ).


ご注意

注釈null_resettableは、プロパティセッターが受け入れることができることを意味しますnilが、プロパティゲッターは代わりnilデフォルト値を返します


Objective-C Swift :



Swift Objective-C :



,


! , :



ご注意

単項論理否定演算子は!、異なるコンテキストを参照するため、考慮されません。


? , :



ご注意

三項条件演算子は?、異なるコンテキストを参照するため、考慮されません。


?? :



おわりに


. , . , null , .


, . ++ Java "", . "" , , "" . , .. , Cogito, ergo sum (. — ", "). , . Swift .


追加資料



UPD: (by Alexander Zimin) init(nilLiteral: ()) :


 var test = Optional<Int>(nilLiteral: ()) 

, Apple .



Source: https://habr.com/ru/post/J338766/


All Articles