if
とlet
を一緒に使用して、欠落している可能性がある値を処理することができます。これらの値はオプションとして表されます。オプションの値には、値が含まれているか、その値が欠落していることを示すnil
が含まれています。値をオプションとしてマークするには、値のタイプの後に疑問符(?
)を書きます。
なぜあなたはオプションの値を使いたいのでしょうか?
Swiftのオプションは、値を保持することも、値を保持しないこともできる型です。オプションは任意の型に?
を追加することによって書かれます。
var name: String? = "Bertie"
オプションと(一般的な)は、理解するのが最も難しいSwiftの概念の1つです。それらがどのように書かれ使われているかのために、彼らが何であるかについて間違った考えを得るのは簡単です。上記のオプションと通常の文字列の作成を比較します。
var name: String = "Bertie" // No "?" after String
構文上、オプションのStringは通常のStringと非常によく似ています。そうではありません。オプションの文字列は、「オプション」設定がオンになっている文字列ではありません。それは特別な種類の文字列ではありません。文字列とオプションの文字列はまったく異なる型です。
これが知っておくべき最も重要なことです:オプションはコンテナの一種です。オプションのStringは、Stringを含むことができるコンテナです。オプションのIntはIntを含むかもしれないコンテナです。小包のようなものとしてオプションを考えてください。あなたがそれを開く前に(またはオプションの言語で「アンラップする」)、あなたはそれに何かが含まれているかどうかわからないでしょう。
Swift標準ライブラリで オプションの実装方法 を確認するには、任意のSwiftファイルに「Optional」と入力して⌘キーを押しながらクリックします。これが定義の重要な部分です。
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
オプションはenum
name__のみで、これは.none
または.some
の2つのケースのうちの1つになります。 .some
であれば、上記の例ではString
"Hello"になるような関連値があります。オプションではGenericsを使って関連付けられた値に型を与えます。オプションの文字列の型はString
name__、Optional
name__、より正確にはOptional<String>
ではありません。
Swiftがオプションを使って行うことはすべて、コードの読み書きをより流暢にするための魔法です。残念ながら、これは実際の動作をあいまいにします。私は後でいくつかのトリックをやります。
注:オプション変数についてよく説明しますが、オプション定数を作成しても問題ありません。私は、作成されている型のタイプを理解しやすくするために、すべての変数にそのタイプをマークしていますが、自分のコードで作成する必要はありません。
オプションを作成するには、折り返したい型の後に?
を追加します。あなた自身のカスタムタイプであっても、どのタイプでもオプションにすることができます。型と?
の間にスペースを入れることはできません。
var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)
// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}
オプションとnil
name__を比較して、値に値があるかどうかを確認できます。
var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
print("There is a name")
}
if name == nil { // Could also use an "else"
print("Name has no value")
}
これは少し混乱します。それは、オプションが何らかのものであることを意味します。それはどちらもゼロか "Bob"です。これは真実ではない、オプションは他のものに変換されません。それをnilと比較することはコードを読みやすくするためのトリックです。オプションがnilに等しい場合、これは単にenumが現在.none
に設定されていることを意味します。
オプションではない変数をnilに設定しようとすると、エラーになります。
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
オプションを見る別の方法は、通常のSwift変数を補完するものです。それらは、値を持つことが保証されている変数の対応物です。 Swiftはあいまいさを嫌う慎重な言葉です。ほとんどの変数は非オプションとして定義されていますが、時にはこれは不可能です。たとえば、キャッシュまたはネットワークから画像をロードするView Controllerを想像してください。 View Controllerが作成された時点では、そのイメージは持っていてもいなくてもかまいません。画像変数の値を保証する方法はありません。この場合は、オプションにする必要があります。これはnil
name__で始まり、イメージが取得されると、オプションの値が取得されます。
オプションを使用すると、プログラマの意図が明らかになります。どのオブジェクトもゼロになる可能性があるObjective-Cと比較して、Swiftでは、値が欠落する可能性がある場合と存在することが保証される場合について明確にする必要があります。
オプションのString
name__は、実際のString
name__の代わりに使用することはできません。オプション内で折り返し値を使用するには、それをアンラップする必要があります。オプションのラップを解除する最も簡単な方法は、オプションの名前の後に!
を追加することです。これを「強制開封」と呼びます。オプションの内部の値を(元の型として)返しますが、オプションがnil
name__の場合、ランタイムクラッシュを引き起こします。展開する前に、価値があることを確認する必要があります。
var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")
name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.
展開してオプションを使用する前に、常にnilをチェックする必要があるため、これが一般的なパターンです。
var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
let unwrappedMealPreference: String = mealPreference!
print("Meal: \(unwrappedMealPreference)") // or do something useful
}
このパターンでは、値が存在することを確認します。そして、値が存在することを確認したら、それを使用する一時定数にアンラップします。これはとても一般的なことなので、Swiftは "if let"を使ったショートカットを提供しています。これは「オプションのバインディング」と呼ばれます。
var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
print("Meal: \(unwrappedMealPreference)")
}
これにより、有効範囲がifの中括弧内にのみ存在する一時定数(またはlet
name__をvar
name__に置き換えた場合は変数)が作成されます。 "unwrappedMealPreference"や "realMealPreference"のような名前を使用しなければならないのは負担が大きいため、Swiftでは元の変数名を再利用して角括弧内に一時的な名前を作成することができます。
var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // separate from the other mealPreference
}
これは、異なる変数が使われていることを示すためのコードです。
var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"
オプションバインディングは、オプションがnilに等しいかどうかを確認することによって機能します。そうでない場合は、オプションを提供された定数に展開してブロックを実行します。 Xcode 8.3以降(Swift 3.1)では、このようにオプションを印刷しようとすると無用な警告が発生します。無音にするには、オプションのdebugDescription
name__を使用します。
print("\(mealPreference.debugDescription)")
オプションには2つのユースケースがあります。
いくつかの具体例:
middleName
name__クラスのspouse
name__またはPerson
name__のように、存在してもしなくてもよいプロパティーweak
name__プロパティの場合。彼らが指すものはいつでもnil
name__に設定することができますBoolean
name__を使用するのではなく、値がいつ設定されたか(データがまだロードされていない>データ)を知る方法が必要な場合OptionalsはObjective-Cには存在しませんが、同等の概念があり、nilを返します。オブジェクトを返すことができるメソッドは、代わりにnilを返すことができます。これは「有効なオブジェクトが存在しない」ことを意味すると解釈され、何かがうまくいかなかったと言うためによく使われます。これはObjective-Cオブジェクトでのみ機能し、プリミティブや基本的なCタイプ(列挙体、構造体)では機能しません。 Objective-Cには、これらの値が存在しないことを表すための特殊な型がよくあります(NSNotFound
name__は実際にはNSIntegerMax
name__、無効な座標を表すkCLLocationCoordinate2DInvalid
、-1
、または負の値も使用されます)。コーダーはこれらの特別な値について知っていなければならないので、それらはそれぞれの場合について文書化され学習されなければならない。メソッドがnil
name__をパラメータとして受け取れない場合は、これを文書化する必要があります。 Objective-Cでは、nil
name__はすべてのオブジェクトがポインタとして定義されていたのと同じようにポインタでしたが、nil
name__は特定の(ゼロ)アドレスを指していました。 Swiftでは、nil
name__はリテラルで、特定の型が存在しないことを意味します。
nil
name__との比較Boolean
name__として任意のオプションを使用することができるようになりました:
let leatherTrim: CarExtras? = nil
if leatherTrim {
price = price + 1000
}
Swiftの最近のバージョンではleatherTrim != nil
を使わなければなりません。どうしてこれなの?問題は、Boolean
name__をオプションでラップできることです。 Boolean
name__がこのような場合
var ambiguous: Boolean? = false
値がない場合と値があるが値がfalse
name__の場合の2種類の "false"があります。 Swiftはあいまいさが嫌いなので、今度はnil
name__に対してオプションを常にチェックする必要があります。
あなたは、オプションのBoolean
name__の意味は何だろうか?他のオプションと同様に、.none
状態は、値がまだ未知であることを示す可能性があります。ネットワークコールのもう一方の端にポーリングに時間がかかるものがあるかもしれません。オプションのブール値は「 Three-Value Booleans 」とも呼ばれます。
Swiftはオプションが機能するようにするためにいくつかのトリックを使います。これら3行の普通に見えるオプションのコードを考えてください。
var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }
これらの行のどれもコンパイルすべきではありません。
String
name__であったとしても、型は異なりますこれらの行が機能することを可能にするオプションの実装の詳細をいくつか見ていきます。
オプションを作成するために?
を使用することは、Swiftコンパイラーによって可能にされる構文糖です。あなたがそれを遠くまでやりたいのであれば、あなたはこのようなオプションを作成することができます:
var name: Optional<String> = Optional("Bob")
これはOptional
name__の最初の初期化子public init(_ some: Wrapped)
を呼び出します。これは、括弧内で使用されている型からオプションの関連型を推測します。
オプションを作成して設定するさらに長い方法:
var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")
nil
name__に設定初期値なしでオプションを作成することも、初期値nil
name__でオプションを作成することもできます(どちらも同じ結果になります)。
var name: String?
var name: String? = nil
Optionalsをnil
name__と等しくすることを許可することは、プロトコルExpressibleByNilLiteral
name__(以前はNilLiteralConvertible
name__と命名されました)によって可能にされます。オプションはOptional
name__の2番目の初期化子public init(nilLiteral: ())
で作成されます。ドキュメントでは、オプション以外の目的でExpressibleByNilLiteral
name__を使用しないでください。コード内のnilの意味が変わるため、それを実行することも可能です。
class Clint: ExpressibleByNilLiteral {
var name: String?
required init(nilLiteral: ()) {
name = "The Man with No Name"
}
}
let clint: Clint = nil // Would normally give an error
print("\(clint.name)")
同じプロトコルで、作成済みのオプションをnil
name__に設定できます。お勧めしませんが、nilリテラル初期化子を直接使用することができます。
var name: Optional<String> = Optional(nilLiteral: ())
nil
name__の比較オプションは2つの特別な "=="と "!="演算子を定義します。これはOptional
name__定義で見ることができます。最初の==
では、任意のオプションがnilと等しいかどうかを確認できます。関連付けられたタイプが同じ場合、.noneに設定されている2つの異なるオプションは常に等しくなります。あなたがnilと比較すると、舞台裏でSwiftは.noneに設定された同じ関連タイプのオプションを作成し、それを比較に使用します。
// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
print("tuxedoRequired is nil")
}
2番目の==
演算子を使用すると、2つのオプションを比較できます。両方とも同じ型である必要があり、その型はEquatable
name__(通常の "=="演算子と比較できるプロトコル)に準拠する必要があります。 Swiftは(おそらく)2つの値をアンラップし、それらを直接比較します。また、一方または両方のオプションが.none
である場合も処理します。 nil
name__リテラルと比較することの違いに注意してください。
さらに、任意のEquatable
name__型を、その型をラップするオプションのものと比較することもできます。
let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
print("It's a match!") // Prints "It's a match!"
}
舞台裏では、Swiftは比較の前に非オプションをオプションとしてラップします。リテラルでも動作します(if 23 == numberFromString {
)
==
演算子は2つありますが、実際には比較の左側にnil
name__を置くことができる3つ目の演算子があります。
if nil == name { ... }
オプションの型に非オプションの型と異なる名前を付けるためのSwift規約はありません。人々はそれがオプションであることを示すために名前に何かを追加することを避け( "optionalMiddleName"や "possibleNumberAsString"のように)、宣言にそれがオプションの型であることを示させます。オプションからの値を保持するために何か名前を付けたい場合、これは難しくなります。 "middleName"という名前はString型であることを意味しているので、そこからString値を抽出すると、 "actualMiddleName"、 "unwrappedMiddleName"、 "realMiddleName"などの名前になることがよくあります。これを回避するには、オプションのバインディングを使用し、変数名を再利用します。
From Swiftプログラミング言語の「基本」 :
Swiftでは、値の欠如を処理するオプションの型も導入されています。オプションには、「値があり、xに等しい」または「値がまったくない」のいずれかがあります。オプションはObjective-Cのポインタでnilを使用するのと似ていますが、クラスだけでなくあらゆるタイプに対して機能します。オプションはObjective-Cのゼロポインタよりも安全で表現力があり、Swiftの最も強力な機能の中心にあります。
オプションは、Swiftがタイプセーフな言語であるという事実の一例です。 Swiftを使用すると、コードで使用できる値の種類を明確に理解できます。コードの一部に文字列が必要な場合は、型安全を使用すると、誤ってIntを渡すことができなくなります。これにより、開発プロセスのできるだけ早い段階でエラーを見つけて修正することができます。
最後に、これはオプションについての1899年からの詩です。
昨日の階段
私はそこにいなかった男に会いました
彼は今日はもうそこにいませんでした
お願いします、彼が去ってほしいのですが
アンティゴニッシュ
NSError
の例を見てみましょう。エラーが返されない場合は、Nilを返すことをオプションにする必要があります。エラーがなければ、値を代入しても意味がありません。
var error: NSError? = nil
これにより、デフォルト値を設定することもできます。そのため、関数に何も渡さない場合は、メソッドにデフォルト値を設定できます。
func doesntEnterNumber(x: Int? = 5) -> Bool {
if (x == 5){
return true
} else {
return false
}
}
Swiftではnil
を指す変数を持つことはできません - ポインタもnullポインタもありません。しかしAPIでは、あなたはしばしば特定の種類の価値、または価値の欠如のどちらかを示すことができることを望みます。私のウィンドウにはデリゲートがありますか?もしそうなら、だれですか? Optionalsはこれを行うためのSwiftのタイプセーフ、メモリセーフな方法です。
私は、初心者として私の頭の中にあった不確実性をきれいにするために、上の大部分を要約する短い答えをしました:
Objective-Cとは対照的に、Swiftではnilを変数に含めることはできません。そのため、Optional変数型が追加されました(変数の末尾に "?"が付きます)。
var aString = nil //error
大きな違いは、(通常のObj-C変数がそうであるように)Optional変数は値を直接格納しないことです2つの状態: "の値が "または"の値がnilの場合:
var aString: String? = "Hello, World!"
aString = nil //correct, now it contains the state "has nil"
つまり、さまざまな状況でこれらの変数を確認できます。
if let myString = aString? {
println(myString)
}
else {
println("It's nil") // this will print in our case
}
「!」を使って接尾辞、それらに囲まれた値にアクセスすることもできます、それらが存在する場合のみ。 (つまり、nilではありません):
let aString: String? = "Hello, World!"
// var anotherString: String = aString //error
var anotherString: String = aString!
println(anotherString) //it will print "Hello, World!"
だからこそ「?」を使う必要があります。そして「!」デフォルトではそれらすべてを使用しません。 (これは私の最大の戸惑いでした)
上記の答えにも同意します。オプションの型をブール値として使用することはできません。
Objective Cでは、値のない変数は 'nil'に等しくなりました(0やfalseと同じ 'nil'値を使うこともできました)。そのため、条件文で変数を使うことができました'と値がないものは' FALSE 'と同じです。
Swiftは「オプションの値」を提供することによって型の安全性を提供します。すなわち、異なるタイプの変数を代入することによって生じるエラーを防止します。
そのため、Swiftでは、条件文にはブール値のみを指定できます。
var hw = "Hello World"
ここで、 'hw'は文字列ですが、Objective Cのようにif文では使用できません。
//This is an error
if hw
{..}
そのためには、次のように作成する必要があります。
var nhw : String? = "Hello World"
//This is correct
if nhw
{..}
オプションの値では、値がないことを示すことができます。 SQLではNULL、Objective-CではNSNullと少し似ています。これは「プリミティブ」タイプにも使用できるので、これは改善になると思います。
// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)”
抜粋:アップル社の "The Swift Programming Language"。 https://itun.es/gb/jEUH0.l
オプションは、Swiftが値が型に対応するかどうかを完全には確実にしないことを意味します。例えば、Int? Swiftは、数値がIntであるかどうかを完全には確信できないことを意味します。
それを削除するには、3つの方法があります。
1)あなたがそのタイプを絶対に確信しているなら、あなたはそれをアンラップするために感嘆符を使うことができます。
// Here is an optional variable:
var age: Int?
// Here is how you would force unwrap it:
var unwrappedAge = age!
オプションのラップを強制的に展開し、それがnilに等しい場合、このクラッシュエラーが発生する可能性があります。
これは必ずしも安全ではないので、型と値がわからない場合にクラッシュしないようにする方法があります。
方法2と3は、この問題から保護します。
2)暗黙的にラップ解除されたオプション
if let unwrappedAge = age {
// continue in here
}
ラップされていない型が Int?ではなく Int になっていることに注意してください。
3)ガードステートメント
guard let unwrappedAge = age else {
// continue in here
}
ここから先に進んで、ラップされていない変数を使用できます。変数の種類が確実な場合は、必ずアンラップ(!を使用)を強制してください。
あなたのプロジェクトで頑張ってください!
Swift
を学び始めたとき、オプションの理由を理解するのは非常に困難でした。
このように考えてみましょう。 2つのプロパティPerson
とname
を持つクラスcompany
を考えてみましょう。
class Person: NSObject {
var name : String //Person must have a value so its no marked as optional
var companyName : String? ///Company is optional as a person can be unemployed that is nil value is possible
init(name:String,company:String?) {
self.name = name
self.companyName = company
}
}
Person
のいくつかのオブジェクトを作成しましょう
var tom:Person = Person.init(name: "Tom", company: "Apple")//posible
var bob:Person = Person.init(name: "Bob", company:nil) // also Possible because company is marked as optional so we can give Nil
ただし、Nil
をname
に渡すことはできません
var personWithNoName:Person = Person.init(name: nil, company: nil)
では、optional?
を使用する理由について説明しましょう。 Inc
がApple Inc
のような会社名の後にApple
を追加する状況を考えてみましょう。会社名の後にInc
を追加して印刷する必要があります。
print(tom.companyName+" Inc") ///Error saying optional is not unwrapped.
print(tom.companyName!+" Inc") ///Error Gone..we have forcefully unwrap it which is wrong approach..Will look in Next line
print(bob.companyName!+" Inc") ///Crash!!!because bob has no company and nil can be unwrapped.
ここで、オプションが実施される理由を調べてみましょう。
if let companyString:String = bob.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
print(companyString+" Inc") //Will never executed and no crash!!!
}
bob
をtom
に置き換えましょう
if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
print(companyString+" Inc") //Will never executed and no crash!!!
}
おめでとうございます!optional?
を適切に処理しました
実現ポイントは
nil
になる可能性がある場合、変数をオプションとしてマークします。nil
が含まれている場合、その変数に適切に対処できるかどうかを確認する必要があることを思い出させます。ありがとう... Happy Coding
以下のコードで試してみましょう遊び場私は、それがオプションで何がそれを使用するのかという考えを明確にするでしょう。
var sampleString: String? ///Optional, Possible to be nil
sampleString = nil ////perfactly valid as its optional
sampleString = "some value" //Will hold the value
if let value = sampleString{ /// the sampleString is placed into value with auto force upwraped.
print(value+value) ////Sample String merged into Two
}
sampleString = nil // value is nil and the
if let value = sampleString{
print(value + value) ///Will Not execute and safe for nil checking
}
// print(sampleString! + sampleString!) //this line Will crash as + operator can not add nil
オプション連鎖は、現在nilになっている可能性があるオプションのプロパティ、メソッド、および添え字を照会および呼び出すためのプロセスです。オプションが値を含む場合、プロパティ、メソッド、または添字の呼び出しは成功します。オプションがnilの場合、プロパティ、メソッド、または添字呼び出しはnilを返します。複数のクエリを連鎖させることができ、チェーン内のいずれかのリンクがnilであると、チェーン全体が正常に失敗します。
より深く理解するために、上のリンクを読んでください。
まあ….
? (省略可能)は、の間に変数にnil値を含めることができることを示します。 (unwrapper)は、実行時に変数が使用されるとき(それから値を取得しようとするとき)、メモリ(または値)が必要であることを示します。
主な違いは、オプションがnilの場合はオプションの連鎖が正常に失敗するのに対し、オプションがnilの場合は強制的な展開でランタイムエラーが発生することです。
オプションの連鎖がnil値に対して呼び出される可能性があるという事実を反映するために、オプションの連鎖呼び出しの結果は、照会しているプロパティー、メソッド、または添え字がオプション以外の値を返す場合でも、常にオプションの値です。このオプションの戻り値を使用して、オプションのチェーン呼び出しが成功した(返されたオプションに値が含まれている)か、チェーン内のnil値のために成功しなかった(返されたオプション値はnil)かを確認できます。
具体的には、オプションの連鎖呼び出しの結果は、予期される戻り値と同じ型ですが、オプションで囲まれています。通常Intを返すプロパティは、オプションのチェーニングを通してアクセスされると、Int?を返します。
var defaultNil : Int? // declared variable with default nil value
println(defaultNil) >> nil
var canBeNil : Int? = 4
println(canBeNil) >> optional(4)
canBeNil = nil
println(canBeNil) >> nil
println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper
var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4
var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error
これがApple Developer Committeeによる基本的なチュートリアルの詳細です: Optional Chaining
Swiftのオプションは、値を保持することも、値を保持しないこともできる型です。オプションは任意の型に?を追加することによって書かれます。
var name: String?
あなたは深い知識を得るためにこのリンクを参照することができます: https://medium.com/@agoiabeladeyemi/optionals-in-Swift-2b141f12f870