我目前的任务是iOS键盘扩展,其中包括所有iOS支持的表情符号(是的,我知道iOS有一个内置表情符号键盘,但目标是在键盘扩展中包含一个).
对于这个基本上应该是以网格顺序包含所有表情符号的滚动视图的表情符号布局,我决定使用UICollectionView,因为它只创建有限数量的单元格并重用它们.(有很多表情符号,超过1000个.)这些单元格只包含一个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的Leaks工具运行键盘.我注意到两件事:
VM: CoreAnimation
滚动时上升到大约6-7MB,但我想在滚动集合视图时这可能是正常的.
Malloc 16.00KB
从千字节的值开始,当滚动整个列表时,最多可弹出17MB,因此分配了大量内存,但我看不到其他任何实际使用它的内容.
但没有报道泄漏.
EDIT2:我刚刚检查过CFGetRetainCount
(在使用ARC时仍然有效),一旦设置了nil值,String对象就没有任何引用了prepareForReuse
.
我正在使用iOS 9.2测试iPhone 5s,但问题也出现在使用iPhone 6s Plus的模拟器中.
编辑3:有人在这里有完全相同的问题,但由于奇怪的标题,我到目前为止没有找到它.似乎唯一的解决方案是在列表中使用UIImageViews和UIImages,因为UICollectionView中的UIImages在单元重用上被正确释放.
这很有意思,在我的测试项目中,我在EmojiView中注释了prepareForReuse部分,内存使用情况变得稳定,项目开始时为19MB,从未超过21MB,(self.contentView.subviews [0]为!UILabel) .text = nil导致我的测试中的问题.