web-dev-qa-db-ja.com

フォースキャストは本当に悪いのですか、それを常に避けるべきですか?

私はswiftLintの使用を開始し、Swift=の強制キャストを回避することがベストプラクティスの1つであることに気付きました。

let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellID, forIndexPath: indexPath) as! MyOffersViewCell

これがベストプラクティスでない場合、これを処理する正しい方法は何ですか? let with as?を使用できると思いますが、それは他の条件では空のセルを返す必要があるということですか?それは受け入れられますか?

if let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellID, forIndexPath: indexPath) as? MyOffersViewCell {
      // code
} else {
      // code
}
33
user3574111

この質問はおそらく意見に基づいているので、私の答えを一言で考えてみましょう。しかし、強制的なダウンキャストがalways悪いとは言いません。特定の状況でセマンティクスとそれがどのように適用されるかを考慮する必要があります。

as! SomeClassは契約であり、基本的には「このことはSomeClassのインスタンスであることを保証します」と言っています。 SomeClassではないことが判明した場合、契約に違反したために例外がスローされます。

この契約を使用しているコンテキストと、強制ダウンキャストを使用しなかった場合に実行できる適切なアクションを検討する必要があります。

あなたが与える例では、dequeueReusableCellWithIdentifierdoes n'tがあなたにMyOffersViewCellを与えるなら、おそらく何かを誤って設定しているでしょうセルの再利用識別子を使用してください。例外はその問題を見つけるのに役立ちます。

条件付きダウンキャストを使用した場合は、nilになり、それを何らかの方法で処理する必要があります-メッセージを記録しますか?例外を投げますか?確かに、回復不能なエラーと、開発中に見つけたい何かを表します。リリース後にこれを処理する必要はないでしょう。コードが突然異なる種類のセルを返し始めることはありません。強制ダウンキャストでコードをクラッシュさせた場合、問題が発生した行をまっすぐ指します。

次に、Webサービスから取得したJSONにアクセスする場合を考えてみましょう。あなたの制御を超えたウェブサービスの変更があるかもしれませんので、これをもっと優雅に扱うのはいいかもしれません。アプリは機能しない可能性がありますが、少なくともクラッシュするだけでなく、アラートを表示できます。

BAD-JSONが配列でないとクラッシュする

 let someArray=myJSON as! NSArray 
 ...

より良い-アラートで無効なJSONを処理する

guard let someArray=myJSON as? NSArray else {
    // Display a UIAlertController telling the user to check for an updated app..
    return
}
47
Paulw11

更新

Swiftlint をしばらく使用した後、今度はZero Force-Unwrapping Cultに完全に変換します(以下の@Kevinのコメントに沿って)。

_if let..._、_guard let... else_、または_switch... case let..._を代わりに使用できないオプションを強制的にアンラップする必要がある状況は実際にはありません。

だから、最近私はこれをするでしょう:

_for media in mediaArray {
    if let song = media as? Song {
        // use Song class's methods and properties on song...

    } else if let movie = media as? Movie {
        // use Movie class's methods and properties on movie...
    }
}
_

...または、_if/else_ sのバグが発生しやすいチェーンよりも網羅的なswitchステートメントの優雅さと安全性を好む場合:

_switch media {
case let song as Song:
    // use Song class's methods and properties on song...
case let movie as Movie:    
    // use Movie class's methods and properties on movie...
default:
    // Deal with any other type as you see fit...
}
_

...または、flatMap()を使用してmediaArrayを2つ(おそらく空)に変換しますtypedタイプ_[Song]_および_[Movie]_の配列。しかし、それは質問の範囲外です(force-unwrap)...

さらに、Table Viewセルをデキューする場合でも、強制的にアンラップしません。デキューされたセルを適切なUITableViewCellサブクラスにキャストできない場合、それはストーリーボードに何か問題があることを意味するため、回復可能なランタイム条件ではありません(むしろ、検出する必要がある開発時エラー修正済み)fatalError()で保釈します。


元の回答(記録用)

Paulw11の答えに加えて、このパターンは完全に有効で、安全で、時には便利です。

_if myObject is String {
   let myString = myObject as! String
}
_

Appleが提供する例:Mediaインスタンスの配列で、SongまたはMovieオブジェクト(Mediaの両方のサブクラス)のいずれかを含むことができます。

_let mediaArray = [Media]()

// (populate...)

for media in mediaArray {
   if media is Song {
       let song = media as! Song
       // use Song class's methods and properties on song...
   }
   else if media is Movie {
       let movie = media as! Movie
       // use Movie class's methods and properties on movie...
   }
_
17
Nicolas Miari

knowの場合、「Force Cast」がその場所になります。たとえば、キャスト先はそのタイプです。

myViewには、タグ1を持つUILabelのサブビューがあることがわかっているとしましょう。安全にUIViewからUILabelにキャストを強制できます。

myLabel = myView.viewWithTag(1) as! UILabel

あるいは、より安全なオプションはガードを使用することです。

guard let myLabel = myView.viewWithTag(1) as? UILabel else {
  ... //ABORT MISSION
}

後者は明らかに悪いケースを処理するため安全ですが、前者は簡単です。したがって、実際には、将来変更される可能性のあるものか、アンラップしているものがその状況でそれをキャストしたいものであるかどうかがわからない場合、ガードは常に正しい選択。

要約すると、それが何であるかを正確に知っている場合は、キャストを強制することができます。

5
Blake Lockley

他の人はより一般的なケースについて書いていますが、この正確なケースの解決策を提供したいと思います:

guard let cell = tableView.dequeueReusableCell(
    withIdentifier: PropertyTableViewCell.reuseIdentifier,
    for: indexPath) as? PropertyTableViewCell
else {
    fatalError("DequeueReusableCell failed while casting")
}

基本的に、guardステートメントで囲み、オプションでas?でキャストします。

3

型を使用していて、期待される型を持ち、常に値を持っていることが確実な場合、強制的にキャストする必要があります。アプリがクラッシュした場合、UIのどの部分であるDequeuing Cellに間違いがあるかを簡単に見つけることができます。

しかし、あなたが知らない型をキャストしようとするとき、それは常に同じ型ですか?それとも常に価値があるのでしょうか?強制的にラップを解除しないでください

どのタイプがそのタイプであるか、またはそのキーの1つに値があるかどうかがわからないサーバーから送信されるJSONのように

悪い英語でごめんなさい、私は自分を改善しようとしています

がんばろう????????