【问题标题】:Can I control how many cells stay in memory in a UICollectionView (Swift)?我可以控制 UICollectionView (Swift) 中有多少单元格留在内存中吗?
【发布时间】:2015-03-03 13:38:20
【问题描述】:

是否可以在内存中保留更多单元格?我在滚动时遇到问题。例如,我可以在内存中保留 3 个屏幕而不是一个单元吗?

如果是这样,怎么能做到这一点?

下面是我的一些单元格的屏幕截图。它只有 3 个标签。它们是自定尺寸的。也许这就是需要这么长时间的原因。

或者很可能是我在collectionView:cellForItemAtIndexPath: 中做错了什么

代码如下:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let wordCell: ReadArticleCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("wordCell", forIndexPath: indexPath) as ReadArticleCollectionViewCell

        wordCell.pronunciationLabelView.hidden = false
        wordCell.pronunciationLabelView.textColor = UIColor.blackColor()
        wordCell.layer.shadowOpacity = 0
        wordCell.layer.shadowRadius = 0
        wordCell.layer.shadowColor = UIColor.clearColor().CGColor
        wordCell.underlineLabelView.backgroundColor = UIColor.blackColor()

        var arrayOfParagraphsOfWordStrings = [[String]]()

        for paragraph in self.arrayOfParagraphsOfSentencesOfWordStrings { 
            arrayOfParagraphsOfWordStrings.append(paragraph.reduce([], +)) //is this my culprit? I am doing this so I can use a 3d array as a 2d array datasource but still later be able to map from the 2d array's index to the corresponding index in the 3d array.
        }

        if let word = arrayOfParagraphsOfWordStrings[indexPath.section][indexPath.row] as String? {

            if let pinyinArrayForWord = self.pinyinArray[indexPath.section][indexPath.row] as String? {

                if let pinyin = convertPinyinNumbersToToneMarks(self.pinyinArray[indexPath.section][indexPath.row]) as String? {
                    wordCell.pronunciationLabelView.text = pinyin
                }
                else {
                    wordCell.pronunciationLabelView.text = self.pinyinArray[indexPath.section][indexPath.row]
                }

                if wordCell.pronunciationLabelView.text == "" {
                    wordCell.pronunciationLabelView.text = "n/a"
                    wordCell.pronunciationLabelView.hidden = true
                }

                if self.pinyinQuantityArray[indexPath.section][indexPath.row] > 1 {
//                  println(pinyinQuantityArray[indexPath.section][indexPath.row])
                    wordCell.pronunciationLabelView.textColor = UIColor.purpleColor()
                }
            }

            if word == "Score Paragraph" {
                wordCell.wordLabelView.hidden = false
                wordCell.pronunciationLabelView.hidden = true
                wordCell.pronunciationLabelView.textColor = UIColor.redColor()
            }

            switch self.wordScoreArray[indexPath.section][indexPath.row] {
            case 5...10:
                wordCell.pronunciationLabelView.hidden = true
            case 1...10:
                wordCell.underlineLabelView.backgroundColor = UIColor.blueColor()
            case (-10)...(-1):
                wordCell.underlineLabelView.backgroundColor = UIColor.greenColor()
            default:
                wordCell.underlineLabelView.backgroundColor = wordCell.underlineLabelView.backgroundColor
            }

            if self.wordTouchedArray[indexPath.section][indexPath.row] == true {
//              wordCell.underlineLabelView.backgroundColor = UIColor.orangeColor()
//              wordCell.layer.shadowOffset = CGSize(width: 10, height: 20)
                wordCell.layer.shadowOpacity = 0.75
                wordCell.layer.shadowRadius = 6
                wordCell.layer.shadowColor = UIColor.yellowColor().CGColor
//              wordCell.underlineLabelView.layer.borderColor = UIColor.blackColor().CGColor
//              wordCell.underlineLabelView.layer.borderWidth = 0.25
//              wordCell.underlineLabelView.layer.shadowColor = UIColor.blackColor().CGColor
//              wordCell.underlineLabelView.layer.shadowOffset = CGSize(width: 1, height: 1)
            }

            if self.wordLookedUpArray[indexPath.section][indexPath.row] == true {
//              wordCell.underlineLabelView.backgroundColor = UIColor.blackColor()
                wordCell.layer.shadowOpacity = 0.75
                wordCell.layer.shadowRadius = 6
                wordCell.layer.shadowColor = UIColor.yellowColor().CGColor
            }

            wordCell.wordLabelView.text = arrayOfParagraphsOfWordStrings[indexPath.section][indexPath.row]
        }

        return wordCell
    }

【问题讨论】:

  • 你应该修改你的代码以避免UI线程中的所有长时间运行的进程。即使您可以增加内存中的屏幕数量,您仍然无法加载将在滚动时显示在屏幕中的第 4 个屏幕。
  • 我确实想避免在 UI 线程中长时间运行进程,但是我是一个编程新手,我只是想把它搞定。现在我只能在主要滞后开始之前滚动不到一英寸。至少如果我在内存中保留更多单元格,我可以进一步滚动,然后阅读一点,然后更多单元格将在后台加载(对吗?),然后我可以再次滚动并阅读更多内容。
  • “这是我的罪魁祸首吗?”是的,就是这个!

标签: ios swift uicollectionview


【解决方案1】:

您应该将此代码移动到 ViewDidload 或 ViewWillAppear(在加载 Collection 视图之前)。每次绘制单元格时都重新调用它。我想这是不必要的。

var arrayOfParagraphsOfWordStrings = [[String]]()

for paragraph in self.arrayOfParagraphsOfSentencesOfWordStrings { 
    arrayOfParagraphsOfWordStrings.append(paragraph.reduce([], +)) //is this my culprit? I am doing this so I can use a 3d array as a 2d array datasource but still later be able to map from the 2d array's index to the corresponding index in the 3d array.
}

【讨论】:

    【解决方案2】:

    例如,我能否在内存中保留 3 个屏幕而不是一个单元格?

    在内存中保留超过一屏的单元格是没有意义的,因为它们一次渲染一屏。单元格代表 MVC 结构中的视图,因此您只需创建所需数量即可。

    另一方面,将单元格的数据保存在内存中是非常有意义的。数据代表MVC中的模型;这就是缓存应该发生的地方。

    现在我只能在主要滞后开始前滚动不到一英寸。

    这是因为collectionView:cellForItemAtIndexPath: 中的代码需要访问尚未缓存在数据源中的数据。要解决此问题,请将准备单元格的代码分为两部分:一部分用于获取和缓存数据并准备您需要的所有内容以制作 UICollectionViewCell 而无需实际制作,另一部分可能需要回收 @987654323 @,快速将其与缓存中的数据配对,并将其发送到UICollectionView

    编辑:(回应问题的编辑)

    var arrayOfParagraphsOfWordStrings = [[String]]()
    for paragraph in self.arrayOfParagraphsOfSentencesOfWordStrings { 
        arrayOfParagraphsOfWordStrings.append(paragraph.reduce([], +))
    }
    

    这是我的罪魁祸首吗?我这样做是为了可以使用 3d 数组作为 2d 数组数据源,但以后仍然能够从 2d 数组的索引映射到 3d 数组中的相应索引。

    是的,这就是问题所在。您对每个单元格执行此转换,然后从中取出一个单词。您应该重构代码以将此特定部分移动到其他位置,将 arrayOfParagraphsOfWordStrings 存储在实例变量中,并在您的 collectionView:cellForItemAtIndexPath: 代码中使用它,而无需为每个单元格重新构建它。

    【讨论】:

    • 也许我问错了问题。怎么样:我可以预加载屏幕外单元格,这样我至少可以在延迟之前滚动一点吗?
    • @webmagnets 您不需要预先制作整个屏幕外单元格,只需制作其中最昂贵的部分(通常是图像)。将这些收集起来,也许可以向前看几个屏幕,并将它们存储在内存中。这样,您的collectionView:cellForItemAtIndexPath: 方法将花费零时间查找昂贵的部件,从而非常快速地转动单元格。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2021-06-24
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    相关资源
    最近更新 更多