swift - UICollectionView 接收到具有不存在的索引路径的单元格的布局属性 : <NSIndexPath: 0x79fe0f20> {length = 2, 路径 = 0 - 4}

标签 swift

当我第一次加载我的 UICollectionView 时没有任何问题,我使用自定义布局和 serachbar,当我搜索一些文本时它崩溃抛出异常,即具有不存在的索引路径的单元格,我使用像下一个代码一样的搜索栏:

import UIKit
import AVFoundation

class CategoryViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UISearchBarDelegate {

    var ListArray : JSON! = []
    var SelectedIds: [Int] = []
    var SearchActive : Bool = false
    var SearchArray = [Int]()

    @IBOutlet weak var SearchCategories: UISearchBar!

    @IBOutlet weak var CategoryCollection: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        if let layout = self.CategoryCollection.collectionViewLayout as? InterestsLayout {
            layout.delegate = self
        }

        self.CategoryCollection.backgroundColor = UIColor.clearColor()
        self.CategoryCollection.contentInset = UIEdgeInsets(top: 18, left: 3, bottom: 10, right: 3)

        // Search Delegate
        self.SearchCategories.delegate = self
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.LoadData()
    }

    func LoadData() {
        MUBService.categoriesList(self) { (categories_list) -> () in

            self.ListArray = categories_list
            self.CategoryCollection.reloadData()

            self.view.hideLoading()

        }
    }

    func dismissKeyboard() {
        view.endEditing(true)
        self.SearchCategories.showsCancelButton = false
    }

    func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
        self.SearchCategories.showsCancelButton = true
        self.SearchActive = true
    }

    func searchBarTextDidEndEditing(searchBar: UISearchBar) {
        self.SearchActive = false
    }

    func searchBarCancelButtonClicked(searchBar: UISearchBar) {
        self.SearchActive = false
        self.dismissKeyboard()
    }

    func searchBarSearchButtonClicked(searchBar: UISearchBar) {
        self.SearchActive = false
    }

    func searchBar(searchBar: UISearchBar, let textDidChange searchText: String) {
        self.SearchArray = []
        for (index, object) in self.ListArray["categories"] {
            let name = object["name"].string!
            if name.localizedStandardContainsString(searchText) == true {
                self.SearchArray.append(Int(index)!)
            }
        }


        if(self.SearchArray.count == 0){
            self.SearchActive = false;
        } else {
            self.SearchActive = true;
        }


        self.CategoryCollection.reloadData()
    }

}

extension CategoryViewController {


    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {

        self.CategoryCollection?.collectionViewLayout.invalidateLayout()
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if(self.SearchActive && self.SearchArray.count > 0) {

            return self.SearchArray.count
        }

        return self.ListArray["categories"].count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {


        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as! CategoryCell

        let row = indexPath.row

        if(self.SearchActive && self.SearchArray.count > 0) {

            let category = self.ListArray["categories"][self.SearchArray[row]]
            cell.configureWithPhoto(category, selected: self.ListArray["selected"])
        }else{

            let category = self.ListArray["categories"][row]
            cell.configureWithPhoto(category, selected: self.ListArray["selected"])
        }
        return cell
    }

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {


        let cell = self.CategoryCollection.cellForItemAtIndexPath(indexPath) as! CategoryCell

        cell.changeBackGroundColor()
        if (cell.is_active == true){
            self.SelectedIds.append(cell.id)
        }else{
            self.SelectedIds.removeObject(cell.id)
        }

    }

    @IBAction func RegisterDidTouch(sender: AnyObject) {

        MUBService.setMyCategories(self.SelectedIds, view_controller: self) { (categories_selected) -> () in
            self.performSegueWithIdentifier("HomeTabBarFromCategoriesSegue", sender: self)

        }
    }
}

extension CategoryViewController : InterestsLayoutDelegate {
    // 1. Returns the photo height
    func collectionView(collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:NSIndexPath , withWidth width:CGFloat) -> CGFloat {

        var row = indexPath.row

        if(self.SearchActive && self.SearchArray.count > 0) {

            row = self.SearchArray[row]
        }

        let category = self.ListArray["categories"][row]
        let url = NSURL(string:category["image"].string!)
        let data = NSData(contentsOfURL:url!)
        let image = UIImage(data:data!)!
        let boundingRect =  CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
        let rect  = AVMakeRectWithAspectRatioInsideRect((image.size), boundingRect)

        return rect.size.height
    }

    // 2. Returns the annotation size based on the text
    func collectionView(collectionView: UICollectionView, heightForAnnotationAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat {

        let annotationPadding = CGFloat(4)
        let annotationHeaderHeight = CGFloat(17)

        var row = indexPath.row
        if(self.SearchActive && self.SearchArray.count > 0) {

            row = self.SearchArray[row]
        }
        let category = self.ListArray["categories"][row]

        let font = UIFont(name: "AvenirNext-Regular", size: 10)!
        let rect = NSString(string: category["name"].string!).boundingRectWithSize(CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
        let commentHeight = ceil(rect.height)
        var height = annotationPadding + annotationHeaderHeight + commentHeight + annotationPadding
        if (height != 70){
            height = 70
        }
        return 70
    }
}

我不明白发生了什么,非常感谢你的帮助

最佳答案

我遇到了同样的问题。这里有一个解释:如果您使用自定义 collectionViewLayout 并且您有布局属性的缓存(最佳实践,因此您不必每次都计算属性),您必须在您的自定义中覆盖 invalidateLayout 方法布局类并清除缓存。

这是我的布局属性数组

private var cache = [UICollectionViewLayoutAttributes]()

这里是重写的方法

    override func invalidateLayout() {
    super.invalidateLayout()
    cache.removeAll()
}

我在我的 textDidChange 委托(delegate)中调用布局失效

    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.characters.count > 0 {
        // search and reload data source
        self.searchBarActive    = true
        self.filterContentForSearchText(searchText)
        self.collectionView?.collectionViewLayout.invalidateLayout()
        self.collectionView?.reloadData()
    }else{
        self.searchBarActive = false
        self.collectionView?.collectionViewLayout.invalidateLayout()
        self.collectionView?.reloadData()
    }
}

关于swift - UICollectionView 接收到具有不存在的索引路径的单元格的布局属性 : <NSIndexPath: 0x79fe0f20> {length = 2, 路径 = 0 - 4},我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35639994/

相关文章:

ios - HKObserverQuery 后台传递在调用completionHandler 后停止工作

ios - deinit 在关闭 View Controller 时在应用程序中调用但不在单元测试中调用

cocoa - 在 Swift 和 init(windowNibName) 中子类化 NSWindowController

ios - 选择器方法没有被调用

ios - Swift 中的异步 NSOperation 依赖

swift - 扩展 NSDecimalNumber 以符合 ExpressibleByStringLiteral 会导致 LLDB RPC 服务器崩溃

ios - LLVM 错误 : Broken function found, 编译中止!存档时

ios - 如何在 SFSafariViewController 或 Webview 中打开 Twitterkit

ios - 通过 Interface Builder 创建填充

iphone - Swift 从数组中删除给定值