如何清除充满表情字符的字体caching?

我正在开发iPhone的键盘扩展。 有一个emoji屏幕与苹果自己的表情符号键盘相似,在UICollectionView中显示了大约800个表情符号字符。

当这个表情符号UIScrollView滚动内存使用增加,不下降。 我正在重新使用单元格,并且在显示800倍的单个表情符号字符进行testing时,在滚动过程中内存不会增加。

使用工具,我发现我的代码中没有内存泄漏,但似乎表情符号字形被caching,根据字体大小可能需要大约10-30MB的内存(研究表明它们实际上是PNG)。 键盘扩展可以使用less量内存,然后才能杀死。 有没有办法清除该字体caching?


编辑

添加代码示例以重现该问题:

 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() } 

在运行和滚动UICollectionView我得到如下的内存使用图: 在这里输入图像说明

我遇到了同样的问题,并通过从/ 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页caching,并释放其他不可见的页面。

我有同样的问题,并尝试了很多事情来释放内存,但没有运气。 我只是根据马修的build议更改了代码。 它工作,没有更多的内存问题,包括我的iPhone 6 Plus。

代码更改很less。 在下面的UILabel子类中find更改。 如果你问我,挑战是获取表情符号图像。 我无法确定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()方法为某些表情符号提供了以“/”开头的奇怪值。 到目前为止,给定链路上的解决scheme没有问题。 使用Swift将表情符号转换为hex值

 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方法不适用于每个表情符号。 所以我最终通过gemoji下载了所有的emojis,并且在字典对象中用emoji本身映射了每个表情符号的图像文件(文件名像1.png,2.png等)。 现在使用下面的方法。

 func getImageFileNo(s: String) -> Int { if Array(emo.keys).contains(s) { return emo[s]! } return -1 } 

我猜你正在使用[UIImage imageNamed:]加载图像,或从它派生的东西。 这会将图像caching在系统caching中。

您需要使用[UIImage imageWithContentsOfFile:]加载它们。 这将绕过caching。

(如果这不是问题,那么你需要在你的问题中包含一些代码,以便我们可以看到发生了什么。)

许多表情符号包含多个unicode标量的序列 。 马修的回答与基本的表情符合得很好,但它只返回像国旗这样的表情符号序列的第一个标量。

下面的代码将得到完整的序列,并创build一个匹配gemoji导出文件名的string。

一些简单的笑脸表情符号也有fe0fselect器。 但是gemoji不会在导出时将这个select器添加到文件名上,所以它应该被删除。

 func emojiToHex(_ emoji: String) -> String { var name = "" for item in emoji.unicodeScalars { name += String(item.value, radix: 16, uppercase: false) if item != emoji.unicodeScalars.last { name += "-" } } name = name.replacingOccurrences(of: "-fe0f", with: "") return name }