Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/39.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 UICollectionView中的高内存使用率_Ios_Iphone_Swift_Memory Management_Uicollectionview - Fatal编程技术网

Ios UICollectionView中的高内存使用率

Ios UICollectionView中的高内存使用率,ios,iphone,swift,memory-management,uicollectionview,Ios,Iphone,Swift,Memory Management,Uicollectionview,我目前的任务是一个iOS键盘扩展,它提供了所有支持iOS的表情符号(是的,我知道iOS有一个内置表情符号键盘,但目标是在键盘扩展中包含一个) 对于这个Emoji布局,基本上应该是一个滚动视图,其中所有的Emoji都按网格顺序排列,我决定使用UICollectionView,因为它只创建有限数量的单元格并重用它们。(有相当多的表情符号,超过1000个。)这些单元格只包含一个UILabel,它将表情符号作为文本保存,并使用手势识别器插入点击的表情符号 然而,当我滚动列表时,我可以看到内存使用量在16

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

对于这个Emoji布局,基本上应该是一个滚动视图,其中所有的Emoji都按网格顺序排列,我决定使用UICollectionView,因为它只创建有限数量的单元格并重用它们。(有相当多的表情符号,超过1000个。)这些单元格只包含一个UILabel,它将表情符号作为文本保存,并使用手势识别器插入点击的表情符号

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

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

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


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

编辑:我猜iOS会将渲染的表情保存在内存中的某个位置,尽管在重用之前将文本设置为
nil
。但我可能完全错了

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

  • VM:CoreAnimation
    在滚动时会上升到大约6-7MB,但我猜在滚动集合视图时这可能是正常的
  • Malloc 16.00KB
    ,从一个以千字节为单位的值开始,滚动整个列表时,最高可达17MB,因此分配了大量内存,但使用它我看不到任何其他内容
但没有泄漏报告

EDIT2:我刚刚用
CFGetRetainCount
(使用ARC时仍然有效)检查了字符串对象在设置
prepareForReuse
中的nil值后没有任何引用

我正在用iOS 9.2在iPhone 5s上进行测试,但问题也出现在使用iPhone 6s Plus的模拟器上


EDIT3:有人遇到了完全相同的问题,但由于标题奇怪,我到目前为止没有找到它。似乎唯一的解决方案是将UIImageView与列表中的UIImages一起使用,因为UICollectionView中的UIImages是在单元重用时正确发布的。

我认为您不会使用故事板来设计集合视图。我四处搜索发现,在填充集合视图单元格之前,需要使用标识符注册该类。尝试对viewDidLoad或其他对象调用以下方法

collectionView.registerClass(UICollectionViewCell.self , forCellWithReuseIdentifier: "emojiCell")

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

由于内存问题,您应该尝试延迟加载标签

// Define an emojiLabel property in EmojiView.h
var emojiLabel: UILabel!

// Lazy load your views in your EmojiView.m
lazy var emojiLabel: UILabel  = {
    var tempLabel: UIImageView = UILabel(frame: self.contentView.frame)
    tempLabel.textAlignment = .Center
    tempLabel.userInteractionEnabled = true
    contentView.addSubview(tempLabel)

    return tempLabel;
}()

override func prepareForReuse() {
    super.prepareForReuse()
    emojiLabel.removeFromSuperview()
    emojiLabel = 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) as! EmojiView
        //Get recently used emojis
        if indexPath.section == 0 {
            cell.emojiLabel.text = recent.keys[recent.startIndex.advancedBy(indexPath.item)]
        //Get emoji from full, hardcoded list
        } else if indexPath.section == 1 {
            cell.emojiLabel.text = emojiList[indexPath.item]
        }
        return cell
    }
这样,当您滚动时,您可以确定标签已被释放

现在我有一个问题。为什么要在表情视图中添加手势识别器?UICollectionView已使用其didSelectItemAtIndexPath:delegate实现此功能。为每个加载的单元格分配额外的手势识别器相当繁重

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

    let cell : UICollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath) as! EmojiView
    // Do stuff here
}
总之,我建议去掉EmojiViews.m中的整个init函数,对标签使用延迟加载,对选择事件使用didSelectItemAtIndexPath:delegate


注意:我不习惯swift,因此我的代码可能包含一些错误。

您是否尝试过使用仪器进行检查??你可以确定记忆的去向。@JasonNam请看我的编辑。好的,实际上一个标签可以保留一些记忆。你有没有试着把细胞数量减少到100个?它会影响内存使用吗?没有未发布的UILabel,这就是问题所在:UICollectionViews(如果如上所述实现)只初始化将同时出现的尽可能多的子视图,然后通过更改内容(在本例中为UILabel.text)重用它们。初始化的UILabel的实际数量为56(调试输出)。内存的使用量与滚动成正比。啊哈,好吧,我刚刚提醒了重复使用的单元格。好的,让我们看看我已经在
init
中这样做了。然而,我正在注册UICollectionViewCell的子类,其他任何东西都没有多大意义。这是如何减少内存使用的呢?细胞重用本身是没有问题的。有趣的是,评论这一点并没有改变我键盘上的任何东西。你在哪个设备上测试?数据源包含多少元素?我刚刚创建了一个1000个字符串的数组,我在模拟器中做的,你能给我你的表情符号字符串列表吗?因为在我的测试中,我只是重复了相同的字符串1000次。这里是:(还不包含多字符表情符号)从28.7MB开始,上升到57.7MB,然后回到49.1MB,唯一的区别是表情符号字符串列表,我相信这是由使用表情符号字体造成的。问题不在于标签本身,但是使用UIKit的字体字形缓存(请参阅我的最新编辑)。集合视图已经使用了单元重用,所以这不是问题所在。然而,我明白你对手势识别器的观点,但这不是什么大问题,因为只有56个细胞同时存在。你仍然是对的。
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath){

    let cell : UICollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath) as! EmojiView
    // Do stuff here
}