Swift 3 - CollectionView数据源未返回有效单元格

时间:2017-02-09 14:49:02

标签: swift swift3 uicollectionview ios10

我正在使用此代码:https://www.youtube.com/watch?v=bNtsekO51iQ,但是当我实现我的数据并使用collectionView.reloadData()时,它会崩溃并显示错误代码*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}'

class ChatLogController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    var userId:Int?
    var position:Int = 0
    var otherAvatar:UIImage = UIImage(named: "defaultAvatar")!
    var otherName:String = ""
    var otherSex:String = ""
    var otherBanned:Int = 0
    var otherBlocked:Int = 0
    var messagesDates:[String] = []
    var messagesText:[String] = []
    var messagesIds:[String] = []
    var messagesPics:[UIImage?] = []
    var messagesSeen:[Int] = []
    var messagesWhoSendIt:[Int] = []
    private let cellId = "cellId"
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView?.register(ChatLogMessageCell.self, forCellWithReuseIdentifier: cellId)
        collectionView!.isPrefetchingEnabled = false
        loadChatsFor(position: position)
    }    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return messagesIds.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as IndexPath) as! ChatLogMessageCell

        cell.messageTextView.text = messagesText[indexPath.row]


            cell.profileImageView.image = UIImage(named: "defaultAvatar")!

            let size = CGSize(width:250,height:1000)
            let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
            let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)

        cell.messageTextView.frame = CGRect(x:48 + 8, y:0, width:estimatedFrame.width + 16, height:estimatedFrame.height + 20)

        cell.textBubbleView.frame = CGRect(x:48, y:0, width:estimatedFrame.width + 16 + 8, height:estimatedFrame.height + 20)

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            let size = CGSize(width:250,height:1000)
            let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
            let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)

        return CGSize(width:view.frame.width, height:estimatedFrame.height + 20)
    }


    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(8, 0, 0, 0)
    }

}

class ChatLogMessageCell: BaseCell {

    let messageTextView: UITextView = {
        let textView = UITextView()
        textView.font = UIFont.systemFont(ofSize: 18)
        textView.text = "Sample message"
        textView.backgroundColor = UIColor.clear
        return textView
    }()

    let textBubbleView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(white: 0.95, alpha: 1)
        view.layer.cornerRadius = 15
        view.layer.masksToBounds = true
        return view
    }()

    let profileImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.layer.cornerRadius = 15
        imageView.layer.masksToBounds = true
        return imageView
    }()

    override func setupViews() {
        super.setupViews()

        addSubview(textBubbleView)
        addSubview(messageTextView)

        addSubview(profileImageView)
        addConstraintsWithFormat(format:"H:|-8-[v0(30)]", views: profileImageView)
        addConstraintsWithFormat(format:"V:[v0(30)]|", views: profileImageView)
        profileImageView.backgroundColor = UIColor.red
    }

}
extension UIView {

    func addConstraintsWithFormat(format: String, views: UIView...) {

        var viewsDictionary = [String: UIView]()
        for (index, view) in views.enumerated() {
            let key = "v\(index)"
            viewsDictionary[key] = view
            view.translatesAutoresizingMaskIntoConstraints = false
        }

        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary))
    }


}
class BaseCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews() {
    }
}

在loadChatsFor中,我从web获取数组数据,并使用collectionView.reloadData(),但是当执行此功能时,它会崩溃我的应用程序。我已经找到了答案,但没有成功。我已经添加了IOS 10函数collectionView!.isPrefetchingEnabled = false在视图中加载了这个答案UICollectionView exception in UICollectionViewLayoutAttributes from iOS7,但也无法正常工作。甚至方法collectionViewLayout在reloadData之前和在reloadData之后的invalidateLayout也没有停止崩溃。那么我还能做些什么让它发挥作用?

我从UITableViewCell进入这个CollectionViewController

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let layout = UICollectionViewFlowLayout()
    let controller = ChatLogController(collectionViewLayout: layout)
    controller.userId = chatUserIds[indexPath.row]
    navigationController?.pushViewController(controller, animated: true)
}

我在tableview的类中添加了UICollectionViewDelegateFlowLayout

1 个答案:

答案 0 :(得分:0)

您没有实施UICollectionViewDataSource的正确cellForItemAt方法。这种方法的签名在Swift 3中就像这样改变了。

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as IndexPath) as! ChatLogMessageCell

    cell.messageTextView.text = messagesText[indexPath.row]


    cell.profileImageView.image = UIImage(named: "defaultAvatar")!

    let size = CGSize(width:250,height:1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)

    cell.messageTextView.frame = CGRect(x:48 + 8, y:0, width:estimatedFrame.width + 16, height:estimatedFrame.height + 20)

    cell.textBubbleView.frame = CGRect(x:48, y:0, width:estimatedFrame.width + 16 + 8, height:estimatedFrame.height + 20)

    return cell
}