我正在为 iPhone 开发键盘扩展。有一个表情符号屏幕表情符号到苹果自己的表情符号键盘,在UICollectionView
中显示约 800 个表情符号。
当这个表情符号UIScrollView
滚动时,内存使用增加并且不会下降。我正在正确地重用单元格,并且当测试显示 800 次的单个表情符号字符时,滚动期间内存不会增加。
使用仪器,我发现我的代码中没有内存泄漏,但似乎表情符号被缓存,可以占用大约 10-30MB 的内存,具体取决于字体大小(研究表明它们实际上是 PNG)。
编辑
添加代码示例以重现问题:
let data = Array("??☺️??????????????????????????????????????????????????????????????????????????????????????✨?????????????????✊✌️?✋???????☝️???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????⭐️☀️⛅️☁️⚡️☔️❄️⛄️????☕️???????????????????????????????????????????????????????????????????????????????????❤️???????????????????????????????????????????????????????????️????⚽️⚾️????⛳️??????????").map {String($0)}
class CollectionViewTestController: UICollectionViewController {
override func viewDidLoad() {
collectionView?.registerClass(Cell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath) as! Cell
if cell.label.superview == nil {
cell.label.frame = cell.contentView.bounds
cell.contentView.addSubview(cell.label)
cell.label.font = UIFont.systemFontOfSize(34)
}
cell.label.text = data[indexPath.item]
return cell
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
}
class Cell: UICollectionViewCell {
private let label = UILabel()
}
After running and scrolling the UICollectionView
I get memory usage graph like this:
我遇到了同样的问题,并通过从 / System / Library / Fonts / Apple Color Emoji.ttf 转储.png 并使用 UIImage(contentsOfFile:String)而不是 String 来修复它。
我使用https://github.com/github/gemoji提取.png 文件,用 @ 3x 后缀重命名文件。
func emojiToHex(emoji: String) -> String {
let data = emoji.dataUsingEncoding(NSUTF32LittleEndianStringEncoding)
var unicode: UInt32 = 0
data!.getBytes(&unicode, length:sizeof(UInt32))
return NSString(format: "%x", unicode) as! String
}
let path = NSBundle.mainBundle().pathForResource(emojiToHex(char) + "@3x", ofType: "png")
UIImage(contentsOfFile: path!)
UIImage (contentsOfFile:path!) 被正确释放,因此内存应该保持在较低的水平。到目前为止,我的键盘扩展还没有崩溃。
如果 UIScrollView 包含大量表情符号,请考虑使用 UICollectionView,它仅在缓存中保留 3 或 4 个页面,并释放其他看不见的页面。
我有同样的问题,并尝试了很多事情来释放内存,但没有运气。我只是根据 Matthew 的建议更改了代码。它的工作原理,对我来说没有更多的内存问题包括 iPhone 6 Plus。
代码的变化是最小的。在的 UILabel 子类中找到变化。如果你问我挑战是获取表情符号图像。我无法弄清楚 gemoji (https://github.com/github/gemoji) 是如何工作的。
//self.text = title //what it used to be
let hex = emojiToHex(title) // this is not the one Matthew provides. That one return strange values starting with "/" for some emojis.
let bundlePath = NSBundle.mainBundle().pathForResource(hex, ofType: "png")
// if you don't happened to have the image
if bundlePath == nil
{
self.text = title
return
}
// if you do have the image
else
{
var image = UIImage(contentsOfFile: bundlePath!)
//(In my case source images 64 x 64 px) showing it with scale 2 is pretty much same as showing the emoji with font size 32.
var cgImage = image!.CGImage
image = UIImage( CGImage : cgImage, scale : 2, orientation: UIImageOrientation.Up )!
let imageV = UIImageView(image : image)
//center
let x = (self.bounds.width - imageV.bounds.width) / 2
let y = (self.bounds.height - imageV.bounds.height) / 2
imageV.frame = CGRectMake( x, y, imageV.bounds.width, imageV.bounds.height)
self.addSubview(imageV)
}
emojiToHex()方法 Matthew 为某些表情符号提供以“/”开头的返回奇怪值。到目前为止,给定链接处的解决方案没有任何问题。Convert emoji to hex value using Swift
func emojiToHex(emoji: String) -> String
{
let uni = emoji.unicodeScalars // Unicode scalar values of the string
let unicode = uni[uni.startIndex].value // First element as an UInt32
return String(unicode, radix: 16, uppercase: true)
}
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
原来这个 emojiToHex 方法并不适用于每个 emoji。所以我最终通过 gemoji 下载所有 emoji 并将每个 emoji 图像文件(文件名如 1.png,2.png 等)与 emoji 本身映射在字典对象中。现在使用以下方法代替。
func getImageFileNo(s: String) -> Int
{
if Array(emo.keys).contains(s)
{
return emo[s]!
}
return -1
}
我猜你正在使用[UIImage imageNamed:]
加载图像,或者从它派生的东西。这将在系统缓存中缓存图像。
您需要使用[UIImage imageWithContentsOfFile:]
加载它们。这将绕过缓存。
(如果这不是问题,那么你需要在你的问题中包含一些代码,以便我们可以看到发生了什么。)
我也在房子周围,经过多次测试,我得出了以下结论:
虽然字体缓存确实有助于扩展的内存占用和 Xcode 调试导航器和内存报告中的总使用量,但它的处理方式与预算的其余部分不同。
然后有些人引用 50 MB 作为扩展限制,在苹果文档上我想我已经看到 30 或 32 MB 引用。我们看到内存警告在 30 和 40 MB 之间的各个点,这是太不一致,不满意任何特定的值,但有一件事似乎是具体的是一个内存异常,发生在 53 MB,这是由 Xcode 注销的,如果我采取一个空白的键盘扩展和填充我的字体 30 MB,我甚至是 yph
从我的观察,字体缓存看起来得到清理,但不是经常,你可能会觉得有必要(特别是如果你变得紧张,当无益的组合内存值超过 30 或 32 MB)。
如果您将自己的内存使用预算为 30 MB,则应该是安全的,前提是您不引入一次性需要 23 MB(即 53-30)的字体字形的情况。这将受到表情符号网格的密集程度甚至使用的字体大小的影响。在这里,通常的理解是,如果您要从表情符号集合视图的一端滚动到另一端,则需要 23 MB 以上的字体大小。
在我的测试中,我试图用更多的字体字形自动轰炸扩展,我想我能够击败字体缓存清理过程,导致崩溃。
因此,考虑到 UICollectionView 的使用情况以及它的滚动速度,如果您真的推送了 30 MB 的内存预算并且滚动得非常快,则可能会使应用程序崩溃。
鉴于上述所有情况-使用完全成熟的键盘扩展,只要我保持自己的(非字体字形)占用空间约 30 MB,即使在快速更改表情符号类别和快速滚动时,我也不会遇到崩溃。但是,我确实会遇到系统内存警告,这对我来说是重新灌输疑问的事情。
与使用UIImage(contentsOfFile)
相比,这种方法的另一个问题是,除了字体缓存正在做什么之外,使用内存报告的整体内存占用来检查您的应用程序会更难。
本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处
评论列表(23条)