ios - UICollectionView 中的高内存使用率

标签 ios iphone swift memory-management uicollectionview

<分区>

我目前的任务是 iOS 键盘扩展,其中包括提供所有 iOS 支持的表情符号(是的,我知道 iOS 有一个内置的表情符号键盘,但目标是在键盘扩展中包含一个)。

对于这个表情符号布局,它基本上应该是一个 ScrollView ,其中所有表情符号都按网格顺序排列,我决定使用 UICollectionView,因为它只创建有限数量的单元格并重复使用它们。 (有相当多的表情符号,超过 1'000。)这些单元格仅包含一个 UILabel,它将表情符号作为其文本,并带有一个 GestureRecognizer 以插入点击的表情符号。

但是,当我滚动列表时,我可以看到内存使用量从 16-18MB 左右激增到超过 33MB。虽然这还不会在我的 iPhone 5s 上触发内存警告,但在其他设备上也可能会触发,因为应用程序扩展只占用非常少的资源。

编辑:有时我会收到内存警告,主要是在切换回“正常”键盘布局时。大多数情况下,切换回来时内存使用量会下降到 20MB 以下,但并非总是如此。

如何减少此表情符号布局使用的内存量?


class EmojiView: UICollectionViewCell {

    //...

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.userInteractionEnabled = true
        let l = UILabel(frame: self.contentView.frame)
        l.textAlignment = .Center
        self.contentView.addSubview(l)
        let tapper = UITapGestureRecognizer(target: self, action: "tap:")
        self.addGestureRecognizer(tapper)
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        //We know that there only is one subview of type UILabel
        (self.contentView.subviews[0] as! UILabel).text = nil
    }
}

//...

class EmojiViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    //...

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        //The reuse id "emojiCell" is registered in the view's init.
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("emojiCell", forIndexPath: indexPath)
        //Get recently used emojis
        if indexPath.section == 0 {
            (cell.contentView.subviews[0] as! UILabel).text = recent.keys[recent.startIndex.advancedBy(indexPath.item)]
        //Get emoji from full, hardcoded list
        } else if indexPath.section == 1 {
            (cell.contentView.subviews[0] as! UILabel).text = emojiList[indexPath.item]
        }
        return cell
    }

    //Two sections: recently used and complete list
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 2
    }

}

let emojiList: [String] = [
    "\u{1F600}",
    "\u{1F601}",
    "\u{1F602}",
    //...
    // I can't loop over a range, there are
    // unused values and gaps in between.
]

如果您需要更多代码和/或信息,请告诉我。

编辑:我的猜测是 iOS 将呈现的表情符号保留在内存中的某个位置,尽管在重用之前将文本设置为 nil。但我可能完全错了......

编辑:按照 JasonNam 的建议,我使用 Xcode 的泄漏工具运行了键盘。在那里我注意到两件事:

  • VM: CoreAnimation 在滚动时增加到大约 6-7MB,但我想这在滚动 Collection View 时可能是正常的。
  • Malloc 16.00KB,从以千字节为单位的值开始,在滚动整个列表时增加到 17MB,因此分配了很多内存,但我什么也看不到否则实际使用它。

但没有泄漏报告。

EDIT2:我刚刚检查了 CFGetRetainCount(在使用 ARC 时仍然有效)一旦 中的值为 nil,String 对象就没有任何引用了prepareForReuse 已设置。

我在装有 iOS 9.2 的 iPhone 5s 上进行测试,但在使用 iPhone 6s Plus 的模拟器中也出现了这个问题。

EDIT3:有人遇到了完全相同的问题 here ,但由于标题奇怪,一直没找到。似乎唯一的解决方案是在列表中使用 UIImageViews 和 UIImages,因为 UICollectionView 中的 UIImages 在单元格重用时被正确释放。

最佳答案

这很有趣,在我的测试项目中,我注释掉了 EmojiView 中的 prepareForReuse 部分,内存使用变得稳定,项目从 19MB 开始,从未超过 21MB,(self.contentView.subviews[0] as !UILabel).text = nil 导致我的测试出现问题。

关于ios - UICollectionView 中的高内存使用率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34317729/

相关文章:

swift - 标签未显示(Swift 4 SpriteKit)

ios - SpriteKit : Questionable results from Time Profiler

ios - 隐藏选项卡的基于导航的应用程序

ios - Swift AVPlayerViewController 添加隔空播放

iphone - iOS - 将自定义 UIView 放入 View Controller 中

iphone - 我们如何使用 Cocos2d 显示 UIViewController 和 UIView?

iphone - iPhone 上的 "Untar"文件

iphone - 使用C#在单点触控iPhone项目上的动画 View

ios - swift 中包含 AWSAPIGatewayResponse 的单元测试方法

swift - 动态 UIWebView 高度和 UITableViewCell 调整大小