Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios CollectionViewCell中标签中的数据有时会在重新加载时刷新,有时则不会_Ios_Swift_Uicollectionview_Uilabel_Uicollectionviewcell - Fatal编程技术网

Ios CollectionViewCell中标签中的数据有时会在重新加载时刷新,有时则不会

Ios CollectionViewCell中标签中的数据有时会在重新加载时刷新,有时则不会,ios,swift,uicollectionview,uilabel,uicollectionviewcell,Ios,Swift,Uicollectionview,Uilabel,Uicollectionviewcell,首先让我说,这似乎是一个常见的问题,所以我已经阅读了从Swift到Obj-C的每一篇文章。在过去的9个小时里,我尝试了很多不同的方法,但我的问题仍然存在 我有一个vc vc1,里面有一个collectionView。在collectionView中,我有一个自定义单元格,其中有一个标签和一个imageView。在cellForItem内部,我有一个属性,该属性也位于自定义单元格的内部,当从datasource[indePath.item]设置该属性时,单元格内部有一个属性观察器,用于设置labe

首先让我说,这似乎是一个常见的问题,所以我已经阅读了从Swift到Obj-C的每一篇文章。在过去的9个小时里,我尝试了很多不同的方法,但我的问题仍然存在

我有一个vc vc1,里面有一个collectionView。在collectionView中,我有一个自定义单元格,其中有一个标签和一个imageView。在cellForItem内部,我有一个属性,该属性也位于自定义单元格的内部,当从datasource[indePath.item]设置该属性时,单元格内部有一个属性观察器,用于设置label和imageView的数据

vc1中有一个按钮可以按下vc2,如果用户从vc2中选择了某个内容,它将通过一个委托传递回vc1。vc2被弹出

正确的数据总是被传回我在调试器中检查了多次

问题是,如果vc1中有一个现有单元格,当新数据添加到数据源时,在我重新加载collectionView后,第一个单元格的标签数据现在显示在新单元格的标签上,新单元格的数据现在显示在旧单元格的标签上

我尝试了从prepareToReuse到删除标签的所有方法,但由于某些原因,只有单元格的标签数据会被混淆。奇怪的是,有时标签会正确更新,而有时则不会?imageView始终显示正确的图像,即使标签数据不正确,我也不会有任何问题。数据源中的两个模型对象始终处于正确的索引位置,并具有正确的信息

有什么问题吗

vc1: UIViewController, CollectionViewDataSource & Delegate {

    var datasource = [MyModel]() // has 1 item in it from viewDidLoad

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

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: customCell, for: indexPath) as! CustomCell

        cell.priceLabel.text = ""
        cell.cleanUpElements()
        cell.myModel = dataSource[indexPath.item]

        return cell
    }

    // delegate method from vc2
    func appendNewDataFromVC2(myModel: MyModel) {

        // show spinner

        datasource.append(myModel) // now has 2 items in it

        // now that new data is added I have to make a dip to fb for some additional information
        firebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in

            if let dict = snapshot.value as? [String: Any] else { }

            for myModel in self.datasource {
                myModel.someValue = dict["someValue"] as? String
            }

            // I added the gcd timer just to give the loop time to finish just to see if it made a difference
            DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {

               self.datasource.sort { return $0.postDate > $1.postDate } // Even though this sorts correctly I also tried commenting this out but no difference
               self.collectionView.reloadData()

               // I also tried to update the layout
               self.collectionView.layoutIfNeeded()

               // remove spinner
            }
        })
    }    
}
下面的自定义单元格。这是myModel属性观察器内部内容的简化版本。标签中显示的数据依赖于其他数据,并且有几个条件决定它。将所有这些添加到cellForItem中会创建一堆代码,这就是为什么我没有更新数据,而是将其添加到cellForItem中,或者将其添加到此处,然后选择在单元格中执行。但正如我前面所说,当我检查数据时,它总是100%正确的。属性观察者始终正常工作

CustomCell: UICollectionViewCell {

    let imageView: UIImageView = {
        let iv = UIImageView()
        iv.translatesAutoresizingMaskIntoConstraints = false
        return iv
    }()

    let priceLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    var someBoolProperty = false

    var myModel: MyModel? {
        didSet {

           someBoolProperty = true

           // I read an answer that said try to update the label on the main thread but no difference. I tried with and without the DispatchQueue
           DispatchQueue.main.async { [weak self] in
                self?.priceLabel.text = myModel.price!
                self?.priceLabel.layoutIfNeeded()  // tried with and without this
           }

           let url = URL(string: myModel.urlStr!)
           imageView.sd_setImage(with: url!, placeholderImage: UIImage(named: "placeholder"))

           // set imageView and priceLabel anchors
           addSubview(imageView)
           addSubview(priceLabel)

           self.layoutIfNeeded() // tried with and without this
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()

        // even though Apple recommends not to clean up ui elements in here, I still tried it to no success
        priceLabel.text = ""
        priceLabel.layoutIfNeeded() // tried with and without this
        self.layoutIfNeeded() // tried with and without this

        // I also tried removing the label with and without the 3 lines above 
        for view in self.subviews {
            if view.isKind(of: UILabel.self) {
                view.removeFromSuperview()
            }
        }
    }

    func cleanUpElements() {
        priceLabel.text = ""
        imageView.image = nil
    }
}

我为添加priceLabel.text=3的所有位置添加了1个断点,一旦collectionView重新加载,数据源中的2个对象的断点总是被命中6次3次。第一次在prepareForReuse中,第二次在cellForItem中,第三次在cleanUpElements中,我不得不重置单元格内的一个属性。即使单元格被重新使用,pricelab.text被清除,该属性仍保持其旧bool值。一旦我通过cellForItem重置它,问题就消失了

10个小时,smh

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

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: customCell, for: indexPath) as! CustomCell

    cell.someBoolProperty = false
    cell.priceLabel.text = ""
    cell.cleanUpElements()
    cell.myModel = dataSource[indexPath.item]

    return cell
}

查看prepareForReuse在您的手机中进行事后清理,而不是在排队时进行清理。@FJdeBrienne Apple建议您不要这样做,但如果您查看问题,我还是尝试了。重新阅读该问题,您将看到prepareToReuse,其中包含清理代码。谢谢你的建议,虽然抱歉,Samaria没有注意到。我很惊讶你说苹果不推荐它,因为它是他们的API函数,专门在重用之前准备一个可重用单元。很高兴你成功了@FJdeBrienne在此处了解更多信息:。新年快乐!谢谢你的提醒,我已经用prepareForReuse做了一段时间了,没有发现任何副作用。似乎它与性能的关系比与功能的关系更大。也祝你新年快乐!