1

今天小部件

我们有一个使用自定义字体的 iOS 8+ 应用程序。TTF 文件与应用程序捆绑在一起。

我们现在正在制作一个 Today 小部件(扩展),它需要使用相同的自定义字体才能正确显示内容。

TTF 文件本身为 142 KB。

使用我的测试数据,使用自定义字体只会绘制 3-4 个字符。

症状

问题是使用这种字体会使小部件使用太多内存,并且小部件会收到一些 didReceiveMemoryWarning 调用,然后被终止。

如果我们使用“HelveticaNeue”字体,一切运行正常,但有问题的字符是根据 HelveticaNeue 而不是自定义字体显示的原因。

在 iOS 模拟器中一切运行良好,但 Stackoverflow 的几个问题/答案让我相信这是很正常的,iOS 内存保护机制只会在设备上启动。

在 iPhone 6 上,该小部件被杀死,内存使用量约为 20 MB,因此我们在这里不多讨论。在 iPhone 4S 上,这个限制似乎更低。

问题

所以问题是是否有解决方法。或者可以调整或查看自定义字体的某些属性。

让主应用程序以某种方式将字体预渲染为磁盘上可以由小部件加载的某些内容(png 文件?)是否有意义?如何做到这一点?

对方法或要研究的东西有什么建议吗?

4

1 回答 1

2

我们一直无法找到减少字体使用的内存的方法。

我们通过使用 ImageMagick 和 perl 脚本为我们正在使用的所有可能的大小和字形生成 png 文件,成功地解决了这个问题。

png 文件放置在具有字体名称和磅值的目录结构中。每个字形都有自己的 png 命名,以十六进制 Unicode 代码点命名。

然后将所有 png 文件放入 Xcode 项目中,并以这种方式结束在包中。

在运行时,我们不使用字体[UIImage imageNamed:]渲染,而是执行 a 并渲染它。

该解决方案性能良好,并且在小部件中使用了有限的内存量。

有几个缺点:

  1. 小部件和主应用程序包变得臃肿:添加了 1000 多个 png 文件(磁盘上 575 KB = 4.7 MB)。我们还不知道这会增加多少应用程序的分布大小。
  2. 我们失去了原始方法的灵活性。新的设备类型或对动态类型的更好支持可能会导致需要更多尺寸,然后我们需要生成更多 png。
  3. 更大的错误风险

生成 png 的脚本是:

#!/usr/bin/perl

use File::Path qw(make_path);

$fontName = "SSSymboliconsBlock";
@sizes = (10, 11, 13, 16, 18);

foreach $size (@sizes) {
    $path = "fontCache/$fontName/$size";
    make_path($path);
    @glyphs = ("1f50d", "1f512", "1f511");

    foreach $glyphNo (@glyphs) {
        $glyph = chr(hex($glyphNo));
        system("convert -background none -fill black -font $fontName.ttf -pointsize $size label:\"$glyph\" $path/$glyphNo.png");
    }
}

要加载图像,它是这样的:

- (UIImage *)loadImageForGlyph:(NSString *)glyph
                      fontName:(NSString *)fontName
                      fontSize:(CGFloat)fontSize
{
    // NSDictionary that translates from a glyph to a string with the hex
    // value of the code point.
    // e.g. glyph = @"", codePoint = @"1f50d"
    NSString * codePoint = self.codePointByGlyph[glyph];
    NSString * path
    = [[[[@"fontCache" stringByAppendingPathComponent:fontName]
       stringByAppendingPathComponent:[@(fontSize) stringValue]]
        stringByAppendingPathComponent:codePoint]
       stringByAppendingPathExtension:@"png"];

    UIImage * img = [UIImage imageNamed:path];

    return img;
}
于 2015-03-23T20:15:46.853 回答