2017-07-21 18 views
0

私はUITableViewを持ち、プロトタイプセルにはUICollectionViewを持っています。各セルにCollectionViewを持つUITableViewで再利用可能なセルを使用していません

MainViewControllerUITableViewMyTableViewCellクラスの委譲であるUICollectionViewのために委任しています。

TableViewCellの内容を更新すると、cell.reloadData()が呼び出され、セル内のcollectionViewの内容がリロードされます。

再利用可能なセルを使用すると、各セルが表示されると、最後のセルの内容が消えてしまいます。次に、URLから正しい内容をロードします。

私は最大で5から10までです。UITableViewCellsです。だから私はUITableViewのために再利用可能な細胞を使わないことにしました。 は、私がこれまでのtableView方法における細胞の作成ラインを変更:

let cell = MyTableViewCell(style: .default, reuseIdentifier:nil) 

それから私は、この機能では、(UICollectionViewのための委任である)MyTableViewCellクラスのエラーを得た:

override func layoutSubviews() { 
    myCollectionView.dataSource = self 
} 

EXC_BAD_INSTRUCTION CODE(code=EXC_I386_INVOP, subcode=0x0) 
fatal error: unexpectedly found nil while unwrapping an Optional value 

MyTableViewCell.swift

import UIKit 
import Kingfisher 
import Alamofire 

class MyTableViewCell: UITableViewCell, UICollectionViewDataSource { 


    struct const { 
     struct api_url { 
      static let category_index = "http://example.com/api/get_category_index/"; 
      static let category_posts = "http://example.com/api/get_category_posts/?category_id="; 
     } 
    } 

    @IBOutlet weak var categoryCollectionView: UICollectionView! 

    var category : IKCategory? 
    var posts : [IKPost] = [] 

    override func awakeFromNib() { 
     super.awakeFromNib() 
     // Initialization code 

     if category != nil { 
      self.updateData() 
     } 
    } 

    override func setSelected(_ selected: Bool, animated: Bool) { 
     super.setSelected(selected, animated: animated) 

     // Configure the view for the selected state 
    } 

    override func layoutSubviews() { 
      categoryCollectionView.dataSource = self 
    } 

    func updateData() { 
     if let id = category?.id! { 
      let url = const.api_url.category_posts + "\(id)" 
      Alamofire.request(url).responseObject { (response: DataResponse<IKPostResponse>) in 
       if let postResponse = response.result.value { 
        if let posts = postResponse.posts { 
         self.posts = posts 
         self.categoryCollectionView.reloadData() 
        } 
       } 
      } 
     } 
    } 

    internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath as IndexPath) as! MyCollectionViewCell 

     let post = self.posts[indexPath.item] 
     cell.postThumb.kf.setImage(with: URL(string: post.thumbnail!)) 
     cell.postTitle.text = post.title 

     return cell 
    } 

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     //You would get something like "model.count" here. It would depend on your data source 
     return self.posts.count 
    } 

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 
     return 1 
    } 

} 

MainViewController.swift

細胞を再利用しないのはなぜ

MyCollectionViewCell.swift

import UIKit 

class MyCollectionViewCell: UICollectionViewCell { 

    @IBOutlet weak var postThumb: UIImageView! 
    @IBOutlet weak var postTitle: UILabel! 

    var category : IKCategory? 

} 

はこれを引き起こしましたか?なぜ私は間違っているのですか?

+0

再利用可能なセルを使用しても問題はありません。次のセルが表示されてから古いデータが表示されないようにするには、データソースを消去するだけです。テーブルセルのコードをすべて投稿してください。問題のトラブルシューティングが簡単になります。 layoutSubviews()はおそらくデータソースを設定する場所ではありません – BJHStudios

+0

@BJHStudiosはソースコード – Hadu

答えて

1

速度を上げるにはいくつかのことがあります。

最初に、再利用可能なセルを使用する行のコメントを外し、再利用不可能なセルを作成するコード行を削除します。ここで再使用可能なセルを使用することは安全です。

第2に、MyTableViewCellで、super.awakeFromNib()コールの直後にコレクションビュー用にdataSourceを設定します。 dataSourceは一度だけ設定する必要がありますが、layoutSubviews()は複数回呼び出される可能性があります。お客様のニーズに合わせてデータソースを設定するのは適切な場所ではありません。

override func awakeFromNib() { 
    super.awakeFromNib() 
    categoryCollectionView.dataSource = self 
} 

すでにセルの作成時に、それを呼び出しているように私は、awakeFromNib()からupdateData()への呼び出しを削除しました。 layoutSubviews()のオーバーライドを削除することもできますが、一般的には、オーバーライドするときにはsuper.layoutSubviews()に電話するように注意してください。

最後に、投稿が間違ったセルに再表示されたように見える理由は、セルが再利用されるとポスト配列が空にならないということです。この問題を解決するには、MyTableViewCellに次のメソッドを追加します。

func resetCollectionView { 
    guard !posts.isEmpty else { return } 
    posts = [] 
    categoryCollectionView.reloadData() 
} 

このメソッドは、配列を空にし、あなたのコレクションビューを再ロードします。配列には現在ポストがないので、updateDataを再度呼び出すまで、コレクションビューは空になります。最後のステップは、その関数をセルのprepareForReuseメソッドで呼び出すことです。 MyTableViewCellに次を追加します。

override func prepareForReuse() { 
    super.prepareForReuse() 
    resetCollectionView() 
} 

私はそれがどうなるか教えてください!

+0

を投稿しました。 1つの小さなことは、新しいセルが空であるように見える場合ですが、もう1つのセルの内容をしばらく表示してから、正しい内容をリロードします。あなたは何が起こっているか考えていますか? – Hadu

+1

@ Hadu - あなたのUITableViewCell/UICollectionViewCellサブクラスで 'prepareForReuse()'をオーバーライドすることで、再利用する前にセルをリセットすることができます:https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse オーバーライドするそれはあなたがスーパーに電話していることを確認してください - 上のリンクの議論を見てください。 – siburb

+1

AppleはprepareForReuse()への呼び出しを移動するように編集されていますが、Appleはセル内容の調整にprepareForReuseを使用しないようにドキュメントに明記しています。しかし、それが正しくcellForRowAtで動作していない場合、私は実際にprepareForReuseに入れても問題は見られません – BJHStudios

関連する問題