How to clear font cache filled with emoji characters?

I am developing keyboard extension for iPhone. There is an emoji screen smilar to Apples own emoji keyboard that shows some 800 emoji characters in UICollectionView.

When this emoji UIScrollView is scrolled the memory usage increases and does not drop down. I am reusing cells correctly and when testing with single emoji character displayed 800 times the memory does not increase during scrolling.

  • NSString property copy or readonly?
  • Multithreading and autorelease pool
  • Why do I get memory warnings with only 7 MB of memory allocated?
  • ARC and releasing object created in method
  • Memory Warning UIImagepickerController IOS 7
  • When is an autoreleased object actually released?
  • Using instruments I found that there is no memory leak in my code but it seems that the emoji glyphs are cached and can take around 10-30MB of memory depending on font size (reseach shows they are actually PNGs). Keyboard extensions can use little memory before they are killed. Is there a way to clear that font cache?


    Adding code example to reproduce the problem:

    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.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:
    enter image description here

    4 Solutions Collect From Internet About “How to clear font cache filled with emoji characters?”

    I ran into the same issue and fixed it by dumping the .png from /System/Library/Fonts/Apple Color Emoji.ttf and using UIImage(contentsOfFile: String) instead of a String.

    I used to extract the .png files, renamed the files with @3x suffix.

    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!) is properly released so the memory should stay at a low level. So far my keyboard extension hasn’t crashed yet.

    If the UIScrollView contains a lot of emoji, consider using UICollectionView that retains only 3 or 4 pages in cache and releases the other unseen pages.

    I had the same issue and tried many things to release the memory, but no luck. I just changed the code based on Matthew’s suggestion. It works, no more memory problem for me including iPhone 6 Plus.

    The code change is minimal. Find the change in the UILabel subclass below. If you ask me the challenge is to get the emoji images. I could not figure how gemoji ( works out yet.

        //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
        // if you do have the image 
            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)
            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)

    The emojiToHex() method Matthew provides returns strange values starting with “/” for some emojis. The solution at the given link work with no problems so far. 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)

    ———- AFTER SOME TIME—-

    It turned out this emojiToHex method does not work for every emoji. So I end up downloading all emojis by gemoji and map each and every emoji image file (file names are like 1.png, 2.png, etc) with the emoji itself in a dictionary object. Using the following method instead now.

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

    I am guessing that you are loading the images using [UIImage imageNamed:], or something that derives from it. That will cache the images in the system cache.

    You need to load them using [UIImage imageWithContentsOfFile:] instead. That will bypass the cache.

    (And if that’s not the problem, then you’ll need to include some code in your question so that we can see what’s happening.)

    Many emojis are represented by sequences that contain more than one unicode scalar. Matthew’s answer works well with basic emojis but it returns only first scalar from the sequences of emojis like country flags.

    The code below will get full sequences and create a string that matches gemoji exported file names.

    Some simple smiley emojis also have the fe0f selector. But gemoji doesn’t add this selector to file names on exporting, so it should be removed.

    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