Swiftのオプション

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







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



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







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



まず、 nil



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







ご注意

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







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







第二に、コンパイル段階で明示的なオプションがチェックされるため、実行時のエラーの数が減ります。 Swiftのオプション変数は、オプション変数と同じ方法で使用することはできません(暗黙的に取得されたオプションを除き、詳細については暗黙的なアンラッピングを参照してください )。 オプションを強制的に通常の値に変換するか、 if let



、 guard 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



列挙には、 .none



とsome(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フェーズにありますself



をCityコンストラクターに渡すことができます。 capitalCity



は暗黙的なオプションです。 追加せずにオプションのコンテキストでアクセスできます!



。







暗黙的に取得されたオプションを使用することの副作用は、「組み込み」 assert



です。何らかの理由でcapitalCity



がnil



状態のままになると、ランタイムエラーとプログラムのクラッシュが発生します。







暗黙的に取得された@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 .








All Articles