2016-04-22 11 views
1

私はカスタムセルを使ってカスタムを作ります。UITableView カスタムセルの各々は、私は、サブクラス内の要素にアクセスするにはどうすればよいcellForRowAtIndexPathスウィフト型鋳造

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

     var cell = FormItemTableViewCell(); 

     if(indexPath.row == 1){ 
      cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell 
     } else { 
      cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell 
     } 



     cell.questionLabel.text = "What is the meaning of life?"; 

     return cell 
    } 

でセルデータを移入するFormItemTableViewCell

のサブクラスしようとしていていますか?

例えば:OneTextFieldTableViewCellがありsegControl ながらTwoOptionTableViewCellはありanswerTextField

答えて

2

あり、この問題のいくつかのまともな答えがあるが、それらのほとんどは一般的な1つの悪いものを持って、彼らはあなたがそれらを使用するにはかなりの唯一の許容可能な場所(あなたができる限り避けるべきで開封されたoptionalsを、強制的に

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    guard let cell = tableView.dequeueReusableCellWithIdentifier("Identifier", forIndexPath: indexPath) as? FormItemTableViewCell else { 
     fatalError("Cell is not of kind FormItemTableViewCell") 
    } 

    switch cell { 
    case let cell as TwoOptionTableViewCell where indexPath.row == 1: 
     // Configure cell, which is an object of class TwoOptionTableViewCell, but only when we are in row 1 
     break 
    case let cell as TwoOptionTableViewCell: 
     // Configure cell, which is an object of class TwoOptionTableViewCell, when the row is anything but 1 
     break 
    case let cell as OneTextFieldTableViewCell: 
     // Configure cell, which is an object of class OneTextFieldTableViewCell 
     break 
    case _: print("The cell \(cell) didn't match any patterns: \(indexPath)") 
    } 

    cell.questionLabel.text = "What is the meaning of life?"; 

    return cell 
} 

今、私はそれが最善の方法だと思うの理由を順を追ってみましょう:これは私がこれを処理するための最良の方法と思われるものである

)IBOutletsです。

まず、すべてのオプションをアンラップしないようにします。すべては、switchケースでうまく解かれません。

テーブルからセルをデキューして(常に実行する必要がある)、それがFormItemTableViewCellのサブクラスであることを確認します。それ以外の場合は、致命的なエラーが発生します。

スイッチケースを使用することにより、必要なクラスにcellをキャストし、同時にそれが必要なインデックスパスであるかどうかをチェックします。したがって、クラスを共有する異なる行のロジックを共有する場合は、indexPath.rowと複数の値を比較できます。 where句を使用しない場合、そのクラスを持つセルが見つかるすべての場所で同じロジックが使用されます。

行に応じて必要な識別子を取得するには、ロジックを追加する必要があります。

+0

私はswitch文のメソッド+1が好きです。セルのデキュー時に力のアンラッピングに問題がありますか?私は、Appleの文書もまた展開していないことを知っています。 https://developer.apple.com/library/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson7.html – Alan

+0

強制的にアンラップされたオプションは、スウィフトの安全チェックを上書きするため、最後の手段となるはずです(これは、最大の機能)、期待していないときにアプリをクラッシュさせる可能性があります。この場合、私はあなたのアプリもクラッシュさせる 'fatalError'を使用していますが、制御された方法で使用されています。そのクラッシュを見ると、どこから来たのか、その理由を知ることができます。 – EmilioPelaez

3

あなたは2つのアプローチのいずれかを使用できます。

1)最良の方法:

if(indexPath.row == 1) { 
     let cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell 
     // the type of cell is TwoOptionTableViewCell. Configure it here. 
     return cell 
    } else { 
     let cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell 
     // the type of cell is TwoOptionTableViewCell. Configure it here. 
     return cell 
    } 

2) cellをスーパークラスとして宣言すれば、このようにダウンキャストする必要があります。

var cell: FormItemTableViewCell 

cell = ... // dequeue and assign the cell like you do in your code. 

if let twoOptionCell = cell as? TwoOptionTableViewCell 
{ 
    // configure twoOptionCell 
} 
else if let oneTextFieldCell = cell as? OneTextFieldTableViewCell 
{ 
    // configure oneTextFieldCell 
} 

return cell 

セルをデキューするコードを追加すると、これはより冗長になります。だから私は個人的に最初のアプローチを好んでお勧めします。

+0

これは良い点ですが、5つ以上の異なるフォーム項目を調べることができるので、1つの方法で非常に多くのリターンステートメントを嫌う傾向があります。 – Alan

0

この場合、条件付きでキャストする必要があります。 、あなたはFormItemTableViewCellとしてセルを定義してやっていた

if indexPath.row == 1 { 
    let cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell 
    // Note that we cast the cell to TwoOptionTableViewCell 
    // access `segControl` here 
    return cell 
} else { 
    let cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell 
    // This cell we cast to OneTextFieldTableViewCell. 
    // access `answerTextField` here 
    return cell 
} 

何を:私は(あなたのテーブルビューのセットアップ方法に応じて)行/セクションの代わりに、== 1の列挙型の値を使用して好きですが、基本的に次の操作を行うことになるでしょう後続のアクセスでは、割り当て中にサブクラスに明示的にキャストしても、そのフォームでのみアクセスされます。

varのように、補足する必要はありません。let cell: FormItemTableViewCellとすることができます。次にif文で、サブクラスの新しいセルを定義して操作し、元のcellに割り当てて返します。これはif文の後に両方のセル型で同じ操作を実行する場合(背景色などを設定するなど、どのサブクラスに関係なく)に便利です。ここで

は、この状況に対処する私のお気に入りの方法です:

enum CellTypes { 
    case TwoOption, OneTextField 
    init(row: Int) { 
    if row == 1 { 
     self = .TwoOption 
    } else { 
     self = .OneTextField 
    } 
    } 

    var reuseIdentifier: String { 
    switch self { 
    case .TwoOption: return "twoOptionReuseIdentifier" 
    case .OneTextField: return "oneTextFieldReuseIdentifier" 
    } 
    } 
} 

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell: FormItemTableViewCell 

    let cellType = CellTypes(row: indexPath.row) 
    switch cellType { 
    case .TwoOption: 
    let twoOptionCell = tableView.dequeueReusableCellWithIdentifier(cellType.reuseIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell 
    // do stuff with the `segControl` 
    cell = twoOptionCell 
    case .OneTextField: 
    let textFieldCell = tableView.dequeueReusableCellWithIdentifier(cellType.reuseIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell 
    // do stuff with the `answerTextField` 
    cell = textFieldCell 
    } 

    // Here do something regardless of which CellType it is: 
    cell.questionLabel.text = "What is the meaning of life?" 

    return cell 
} 
1

私が正しく理解し、あなたは一般的なプロパティにアクセスするFormItemTableViewCellとして、細胞の主要な宣言を保持する場合。

新しい変数を作成し、それをキャストしたバージョンに割り当てることができます。 これは同じ参照を指すクラスオブジェクトなので、このインスタンスであなたのものを行います。

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    var cell = FormItemTableViewCell(); 
    // this can be replaced with below line as I don't see the purpose of creating an instance here while you use dequeue below. 
    // var cell: FormItemTableViewCell! 

    if(indexPath.row == 1){ 
     cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath); 
     let tempCell = cell as! TwoOptionTableViewCell; 
     // access members of TwoOptionTableViewCell on tempCell 
     tempCell.segControl.someProperty = 0; 
    } else { 
     cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath); 
     let tempCell = cell as! OneTextFieldTableViewCell; 
     // access members of OneTextFieldTableViewCell on tempCell 
     tempCell.answerTextField.text = "42"; 
    } 



    cell.questionLabel.text = "What is the meaning of life?"; 

    return cell 
} 
+0

ありがとう!私はあなたが人生の意味を知ってうれしいです。 – Alan