私はSwiftをいじってみましたが、ディクショナリに挿入するオブジェクトをダウンキャストすると、奇妙な警告が表示されます:_Treating a forced downcast to 'String' as optional will never produce 'nil'
_。as
__as?
_を使用すると、警告は表示されなくなります。
_func test() -> AnyObject! {
return "Hi!"
}
var dict = Dictionary<String,String>()
dict["test"]=test() as String
_
Appleのドキュメントには次のように書かれています
ダウンキャストは失敗する可能性があるため、型キャスト演算子には2つの異なる形式があります。オプションの形式_
as?
_は、ダウンキャストしようとしている型のオプションの値を返します。強制フォームas
は、ダウンキャストを試み、結果を単一の複合アクションとして強制的にアンラップします。
ここで、なぜas
の代わりに_as?
_を使用するのが正しいのか、はっきりしません。一部のテストでは、test()を変更してStringではなくIntを返すようにした場合、as
を使い続けるとコードがエラーで終了することがわかります。 _as?
_の使用に切り替えると、コードは通常どおり実行を続け、そのステートメントをスキップします(dictは空のままです)。しかし、なぜこれが望ましいのかはわかりません。私の意見では、私はむしろプログラムをエラーで終了し、キャストが失敗したことを知らせてから、単に誤ったステートメントを無視して実行を続けます。
ドキュメントによると、「ダウンキャストが常に成功することが確実である場合にのみ」強制フォームを使用する必要があります。この場合、test()
は文字列のみを返すことができるため、ダウンキャストは常に成功するので、これは強制的な形式のダウンキャストに最適な状況であると思います。では、コンパイラが警告を表示するのはなぜですか?
最後の行を詳しく見て、それを分解して何が起こっているかを見てみましょう。
_let temporaryAnyObject = test()
let temporaryString = temporaryAnyObject as String
dict["test"] = temporaryString
_
エラーは2行目にあり、temporaryAnyObject
がString
であることを強制するようコンパイラーに指示しています。コードは引き続きコンパイルされます(警告をエラーとして扱わないと想定)が、temporaryAnyObject
が実際にString
でない場合はクラッシュします。
_?
_なしでas
が機能する方法は、基本的には「今後、この式の結果をその型として扱います。結果が実際にその型である場合、そうでない場合、一貫性がなくなり、実行できなくなります。 。
_as?
_の動作方法(_?
_を使用)は、「今後、この式の結果をその型として扱います。結果が実際にその型の場合、そうでない場合、この式の結果はnil
になります。 。
したがって、上記の分解例では、test()
がString
を返す場合、as
ダウンキャストは成功し、temporaryString
はString
になりました。 test()
がString
を返さないが、Int
またはStringからサブクラス化されていない何かを言うと、as
は失敗し、コードは実行を継続できなくなります。
これは、開発者が完全に制御できるように、オプションの_?
_インジケーターを配置しないことにより、システムにこのように動作するように指示したためです。 as
コマンドは、オプションの動作を許容せず、そのダウンキャストが機能する必要があることを具体的に意味します。
_?
_を指定した場合、temporaryString
はnil
になり、3行目は "test"キー/値のペアをディクショナリから単純に削除します。
これは奇妙に思えるかもしれませんが、これは、デフォルトですべてをオプションとして扱い、独自のチェックとアサートを配置することに依存しているObj-Cなどの多くの言語のデフォルトの動作とは逆であるためです。
編集-Swift 2更新
Swift 2なので、強制的に失敗する可能性のあるダウンキャスト演算子as
が削除され、Swiftierである_as!
_に置き換えられました。動作は同じです。
この警告は2つの角度から解決できます。 1.返される値2.返される値が期待されるタイプもう1つの答えは、第1の角度についてです。私は第二の角度について話している
これは、オプションに対して強制アンラップおよびキャスト値を返すためです。コンパイラは「本当にすべてのオプションを強制的にキャストしたい場合は、期待される戻りパラメータをnon-optional」
例えばあなたが書いた場合
func returnSomething<T> -> T?{ // I'm an optional, I can handle nils SAFELY and won't crash.
return UIViewController as! T // will never return a safe nil, will just CRASH
}
基本的に、あなたは自分自身(そしてコンパイラー)にnil
sを安全に処理したいと言いましたが、次の行で、いや、そうではありません!!!
コンパイラは警告を出します:
強制ダウンキャストをオプションとして「T」に処理しても、「nil」は生成されません。
代わりに、?
func returnSomething<T>() -> T{ // I can't handle nils
return UIViewController() as! T // I will crash on nils
}
そうは言っても、おそらく最善の方法は、フォースキャストを使用せず、ただ実行することです。
func returnSomething<T>() -> T?{ // I can handle nils
return UIViewController() as? T // I won't crash on nils
}
数年前にこの警告についてバグが開いているようです... https://bugs.Swift.org/browse/SR-4209 ですから、何が明らかかという状況でも表示されますあなたがやっていると正しい。