回答:
実際的な違いはこれです:
var optionalString = dict["SomeKey"] as? String
optionalString
型の変数になりますString?
。基本となるタイプがa以外の場合、String
これは無害nil
にオプションに割り当てます。
var optionalString = dict["SomeKey"] as! String?
これは言う、私はこれがであることを知っていString?
ます。これもoptionalString
の型String?
になりますが、基になる型が他のものである場合はクラッシュします。
次に、最初のスタイルを使用しif let
て、オプションを安全にアンラップします。
if let string = dict["SomeKey"] as? String {
// If I get here, I know that "SomeKey" is a valid key in the dictionary, I correctly
// identified the type as String, and the value is now unwrapped and ready to use. In
// this case "string" has the type "String".
print(string)
}
as? Types
-ダウンキャストプロセスがオプションであることを意味します。プロセスは成功するかどうか(ダウンキャストが失敗した場合、システムはnilを返します)。ダウンキャストが失敗した場合でも、どのような方法でもクラッシュしません。
as! Type?
-ここで、ダウンキャストのプロセスは成功するはずです(それを!
示します)。最後の疑問符は、最終結果がnilになるかどうかを示します。
「!」に関する詳細情報 そして「?」
2つのケースを取ってみましょう
検討してください:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
ここでは、識別子「Cell」のセルをUITableViewCellにダウンキャストした結果が成功したかどうかはわかりません。失敗した場合はnilを返します(ここではクラッシュを回避します)。ここでは、以下のように実行できます。
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell {
// If we reached here it means the down casting was successful
}
else {
// unsuccessful down casting
}
ですから、このように覚えておきましょう。つまり、?
値がnilかどうかわからない場合(疑問符は、物事がわからないときに表示されます)。
対照的に:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell.
ここでは、ダウンキャストが成功するようにコンパイラーに指示します。失敗すると、システムがクラッシュします。そのため!
、値がnilでないことが確実な場合に与えます。
ヴァカワマが言ったことを明確にするために、ここに例があります...
Swift 3.0:
import UIKit
let str_value: Any = String("abc")!
let strOpt_value: Any? = String("abc")!
let strOpt_nil: Any? = (nil as String?)
let int_value: Any = Int(1)
let intOpt_value: Any? = Int(1)
let intOpt_nil: Any? = (nil as Int?)
// as String
//str_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//int_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
// as? String
str_value as? String // == "abc"
strOpt_value as? String // == "abc"
strOpt_nil as? String // == nil
int_value as? String // == nil
intOpt_value as? String // == nil
intOpt_nil as? String // == nil
// as! String
str_value as! String // == "abc"
strOpt_value as! String // == "abc"
//strOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
//int_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
// as String?
//str_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//strOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//strOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//int_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//intOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//intOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
// as? String?
//str_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
strOpt_value as? String? // == "abc"
strOpt_nil as? String? // == nil
//int_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
intOpt_value as? String? // == nil
intOpt_nil as? String? // == nil
// as! String?
//str_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
strOpt_value as! String? // == "abc"
strOpt_nil as! String? // == nil
//int_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//intOpt_value as! String? // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
intOpt_nil as! String? // == nil
// let _ = ... as String
//if let _ = str_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = int_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
// let _ = ... as? String
if let _ = str_value as? String { true } // true
if let _ = strOpt_value as? String { true } // true
if let _ = strOpt_nil as? String { true } // false
if let _ = int_value as? String { true } // false
if let _ = intOpt_value as? String { true } // false
if let _ = intOpt_nil as? String { true } // false
// let _ = ... as! String
//if let _ = str_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = int_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
// let _ = ... as String?
//if let _ = str_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = strOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = int_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = intOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
// let _ = ... as? String?
//if let _ = str_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = strOpt_value as? String? { true } // true
if let _ = strOpt_nil as? String? { true } // true
//if let _ = int_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = intOpt_value as? String? { true } // false
if let _ = intOpt_nil as? String? { true } // true
// let _ = ... as! String?
//if let _ = str_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = strOpt_value as! String? { true } // true
if let _ = strOpt_nil as! String? { true } // false
//if let _ = int_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//if let _ = intOpt_value as! String? { true } // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
if let _ = intOpt_nil as! String? { true } // false
Swift 2.0:
import UIKit
let str: AnyObject = String("abc")
let strOpt: AnyObject? = String("abc")
let strNil: AnyObject? = (nil as String?)
let int: AnyObject = Int(1)
let intOpt: AnyObject? = Int(1)
let intNil: AnyObject? = (nil as Int?)
str as? String // == "abc"
strOpt as? String // == "abc"
strNil as? String // == nil
int as? String // == nil
intOpt as? String // == nil
intNil as? String // == nil
str as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
strOpt as! String? // == "abc"
strNil as! String? // == nil
int as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
intOpt as! String? // Run-Time Error: Could not cast value of type '__NSCFNumber' to 'NSString'
intNil as! String? // == nil
intNil as! String? // ==nil
クラッシュを引き起こさない!!! ???、Optional <Int> .NoneはOptional <String>
as?
するのString
ですか?にダウンキャストしてみませんString?
か?にダウンキャストas!
してみませんString
か?
Any
代わりに使用する必要がありますAnyObject
as
ブリッジ型へのアップキャストおよび型キャストに使用as?
安全なキャストに使用され、失敗した場合はnilを返しますas!
強制的にキャストするために使用され、失敗した場合はクラッシュします注意:
as!
rawタイプをオプションにキャストできませんlet rawString: AnyObject = "I love swift"
let optionalString: AnyObject? = "we love swift"
let nilString: AnyObject? = (nil as String?)
let rawInt: AnyObject = Int(3)
let optionalInt: AnyObject? = Int(3)
let nilInt: AnyObject? = (nil as Int?)
例
var age: Int? = nil
var height: Int? = 180
?を追加することにより データ型の直後に、変数に数値が含まれるかどうかがコンパイラに通知されます。きちんと!オプションの定数を定義することは実際には意味がないことに注意してください。値を設定できるのは1回だけなので、値をnilにするかどうかを指定できます。
UIKitベースのシンプルなアプリがあるとします。ビューコントローラーにコードがあり、その上に新しいビューコントローラーを表示したいと考えています。ナビゲーションコントローラを使用して、画面に新しいビューをプッシュすることを決定する必要があります。
ご存知のように、すべてのViewControllerインスタンスにはプロパティナビゲーションコントローラがあります。ナビゲーションコントローラーベースのアプリを構築している場合、アプリのマスタービューコントローラーのこのプロパティは自動的に設定され、ビューコントローラーをプッシュまたはポップするために使用できます。単一のアプリプロジェクトテンプレートを使用する場合-自動的に作成されるナビゲーションコントローラーがないため、アプリのデフォルトのビューコントローラーには、navigationControllerプロパティに何も格納されません。
これがOptionalデータ型の場合とまったく同じであることは、すでにご想像のとおりと思います。UIViewControllerをチェックすると、プロパティが次のように定義されていることがわかります。
var navigationController: UINavigationController? { get }
それでは、ユースケースに戻りましょう。ビューコントローラーに常にナビゲーションコントローラーがあることがわかっている場合は、先に進んで強制的にアンラップできます。
controller.navigationController!.pushViewController(myViewController, animated: true)
あなたが置くとき!プロパティ名の後ろでコンパイラーにこのプロパティがオプションであることは気にしません、私はこのコードが実行されるとき常に値ストアがあるので、このOptionalを通常のデータ型のように扱います。まあそれはいいことではないですか?ビューコントローラーへのナビゲーションコントローラーがない場合はどうなりますか?あなたがnavigationControllerに保存されている値が常に存在することを示唆している場合は間違っていましたか?アプリがクラッシュします。そのようにシンプルで醜い。
したがって、使用してください!これが安全であると101%確信している場合のみ。
ナビゲーションコントローラーが常にあるかどうかわからない場合はどうでしょうか?その後、使用できますか?!の代わりに:
controller.navigationController?.pushViewController(myViewController, animated: true)
なに?プロパティ名の後ろは、このプロパティにnilと値のどちらが含まれているかがわからないことをコンパイラに通知するため、値がある場合はそれを使用し、そうでなければ式全体をnilと見なします。効果的に?ナビゲーションコントローラがある場合にのみ、そのプロパティを使用できます。あらゆる種類のチェックや、あらゆる種類のキャスティングはありません。この構文は、ナビゲーションコントローラーの有無に関係なく、存在する場合にのみ何かを実行する場合に最適です。
これらはSwiftの2つの異なる形式のダウンキャスティングです。
(as?
)は条件付きフォームであることがわかっており、ダウンキャストしようとしている型のオプションの値を返します。
ダウンキャストが成功するかどうかわからない場合に使用できます。この形式の演算子は常にオプションの値を返します。ダウンキャストが不可能であった場合、値はnilになります。これにより、ダウンキャストが成功したかどうかを確認できます。
(as!
)は強制フォームであることがわかっており、ダウンキャストを試み、結果を単一の複合アクションとして強制的にアンラップします。
ダウンキャストが常に成功することが確実な場合にのみ使用してください。この形式の演算子は、不適切なクラスタイプにダウンキャストしようとすると、ランタイムエラーをトリガーします。
詳細については、Appleのドキュメントの「型キャスト」セクションを確認してください。
たぶんこのコード例は誰かが原理を理解するのに役立つでしょう:
var dict = [Int:Any]()
dict[1] = 15
let x = dict[1] as? String
print(x) // nil because dict[1] is an Int
dict[2] = "Yo"
let z = dict[2] as! String?
print(z) // optional("Yo")
let zz = dict[1] as! String // crashes because a forced downcast fails
let m = dict[3] as! String?
print(m) // nil. the forced downcast succeeds, but dict[3] has no value
1つは「条件付きキャスト」です(私がリンクしたドキュメントの「型キャスト演算子」の下にあります)。キャストが成功した場合、式の値はオプションでラップされて返されます。それ以外の場合、返される値はnilです。
2番目は、optionalStringが文字列オブジェクトであるか、nilである可能性があることを意味します。
Swiftでこれらの演算子のパターンを覚えるのが最も簡単な場合があります。!
「これはトラップする?
可能性があります」を意味し、「これはnilである可能性があります」を示します。
私はSwiftの初心者であり、「オプション」について理解しているときに説明しようとするこの例を書いています。私が間違っている場合は修正してください。
ありがとう。
class Optional {
var lName:AnyObject! = "1"
var lastName:String!
}
let obj = Optional()
print(obj.lName)
print(obj.lName!)
obj.lastName = obj.lName as? String
print(obj.lastName)
(1): obj.lastName = obj.lName as! String
対
(2): obj.lastName = obj.lName as? String
回答:(1)ここでプログラマーは、“obj.lName”
文字列型オブジェクトが含まれていることを確信しています。したがって、その値をに与えるだけ“obj.lastName”
です。
さて、プログラマが正しい手段であれば"obj.lName"
文字列型オブジェクトであれば問題ありません。「obj.lastName」は同じ値に設定されます。
しかし、プログラマーが間違っている場合"obj.lName"
は、文字列型オブジェクトではありません。つまり、「NSNumber」などの他の型オブジェクトが含まれています。クラッシュ(実行時エラー)。
(2)プログラマは、“obj.lName”
文字列型オブジェクトまたはその他の型オブジェクトが含まれていることを確認していません。“obj.lastName”
文字列型の場合は、その値を設定します。
さて、プログラマが正しい手段であれば“obj.lName”
文字列型オブジェクトであれば問題ありません。“obj.lastName”
同じ値に設定されます。
しかし、プログラマーが間違っている場合は、obj.lNameが文字列型オブジェクトではないことを意味します。つまり、他の型オブジェクトが含まれています"NSNumber"
。その後“obj.lastName”
、nil値に設定されます。だから、クラッシュなし(Happy :)