Swiftで次の場合:
var optionalString: String?
let dict = NSDictionary()
次の2つのステートメントの実際の違いは何ですか。
optionalString = dict.objectForKey("SomeKey") as? String
vs
optionalString = dict.objectForKey("SomeKey") as! String?
実際の違いは次のとおりです。
var optionalString = dict["SomeKey"] as? String
optionalString
はString?
型の変数になります。基になる型がString
以外の場合、これは無害にnil
をオプションに割り当てます。
var optionalString = dict["SomeKey"] as! String?
これは、IknowこのことはString?
であると言います。これもoptionalString
がString?
型になります。but基になる型が他の型である場合はクラッシュします。
次に、最初のスタイルを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)
}
バカワマが言ったことを明確にするために、ここに例があります...
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
as? Types
-ダウンキャストプロセスがオプションであることを意味します。プロセスは成功する場合も失敗する場合もあります(ダウンキャストが失敗した場合、システムはnilを返します)。ダウンキャストが失敗した場合、どの方法でもクラッシュしません。
as! Type?
-ここで、ダウンキャストのプロセスは成功するはずです(!
はそれを示します)。最後の疑問符は、最終結果がゼロになるかどうかを示します。
「!」および「?」に関する詳細情報
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のDowncastingの2つの異なる形式です。
(as?
)、これはConditional Form、ダウンキャストしようとしているタイプのオプションの値を返します。
ダウンキャストが成功するかどうかわからない場合に使用できます。この形式の演算子は常にオプションの値を返し、ダウンキャストが不可能な場合、値はnilになります。これにより、ダウンキャストの成功を確認できます。
(as!
)、これはForced Form、ダウンキャストを試み、結果を単一の複合アクションとして強制的にアンラップします。
ダウンキャストが常に成功することが確実な場合は、のみを使用する必要があります。この形式の演算子は、誤ったクラスタイプにダウンキャストしようとすると、ランタイムエラーをトリガーします。
詳細については、AppleのドキュメントのType Castingセクションを確認してください。
as
は、アップキャストおよびブリッジ型への型キャストに使用されますas?
は安全なキャストに使用され、失敗した場合はnilを返しますas!
はキャストの強制に使用され、失敗するとクラッシュします注意:
as!
は生のタイプをオプションにキャストできません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回だけなので、値がゼロかどうかを判断できます。
uIKitベースのシンプルなアプリがあるとします。 View Controllerにいくつかのコードがあり、その上に新しいView Controllerを表示したいと考えています。そして、Navigation Controllerを使用して画面に新しいビューをプッシュすることを決定する必要があります。
知っているように、すべてのViewControllerインスタンスにはプロパティナビゲーションコントローラーがあります。 Navigation Controllerベースのアプリを構築している場合、アプリのマスターView Controllerのこのプロパティは自動的に設定され、View Controllerのプッシュまたはポップに使用できます。単一のアプリプロジェクトテンプレートを使用する場合、Navigation Controllerは自動的に作成されないため、アプリのデフォルトのView ControllerにはnavigationControllerプロパティに何も保存されません。
これは、オプションのデータ型の場合とまったく同じであると既に推測していると思います。 UIViewControllerをチェックすると、プロパティが次のように定義されていることがわかります。
var navigationController: UINavigationController? { get }
それでは、ユースケースに戻りましょう。 View Controllerに常にNavigation Controllerがあることを知っている場合は、先に進み、強制的にアンラップできます:
controller.navigationController!.pushViewController(myViewController, animated: true)
あなたが置くとき!コンパイラに伝えるプロパティ名の後ろにこのプロパティがオプションであることは気にしませんこのオプションを通常のデータ型と同様に扱います。 View ControllerにNavigation Controllerがない場合はどうなりますか? navigationControllerに常に値が保存されるという提案が間違っていましたか?アプリがクラッシュします。そのようにシンプルでい。
だから、使用してください!これが安全であることを101%確信している場合のみ。
ナビゲーションコントローラーが常に存在するかどうかわからない場合はどうでしょうか。次に使用できますか? !:の代わりに
controller.navigationController?.pushViewController(myViewController, animated: true)
なに?プロパティ名の後ろには、コンパイラがであることが示されています式全体を考慮nil。事実上? Navigation Controllerがある場合にのみ、そのプロパティを使用できます。あらゆる種類のチェックまたはあらゆる種類の鋳物の場合、いいえ。この構文は、Navigation Controllerを使用しているかどうかを気にせず、存在する場合にのみ何かをしたいときに最適です。
Fantageek に多大な感謝
たぶん、このコード例は誰かが原理を理解するのに役立つでしょう:
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
最初は「条件付きキャスト」です(リンクしたドキュメントの「型キャスト演算子」の下を見てください) 。キャストが成功した場合、式の値はオプションでラップされて返されます。それ以外の場合、返される値はnilです。
2番目は、optionalStringが文字列オブジェクトであったり、nilであったりすることを意味します。