<分区>
我目前的任务是 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 在单元格重用时被正确释放。