gpt4 book ai didi

objective-c - 在 AppKit 中测量文本宽度的性能

转载 作者:太空狗 更新时间:2023-10-30 03:26:45 26 4
gpt4 key购买 nike

AppKit 中有没有一种方法可以非常快速地测量大量 NSString 对象(比如一百万个)的宽度?我已经尝试了 3 种不同的方法来做到这一点:

  • [NSString sizeWithAttributes:]
  • [NSAttributedString size]
  • NSLayoutManager (获取文本宽度而不是高度)

    以下是一些性能指标

    Count\Mechanism    sizeWithAttributes    NSAttributedString    NSLayoutManager
    1000               0.057                 0.031                 0.007
    10000              0.329                 0.325                 0.064
    100000             3.06                  3.14                  0.689
    1000000            29.5                  31.3                  7.06



    NSLayoutManager 显然是要走的路,但问题是

  • 高内存占用量(根据分析器超过 1GB)因为创建了重量级 NSTextStorage 对象。
  • 创建时间长。所有花费的时间都是在创建上述字符串的过程中,这本身就是一个破坏因素。(随后测量具有创建和布局的字形的 NSTextStorage 对象只需要大约 0.0002 秒)。
  • 7 秒对于我正在尝试做的事情来说仍然太慢。有没有更快的方法?要在大约一秒钟内测量一百万根弦?

    如果你想玩,Here是github项目。

  • 最佳答案

    这里有一些我没有尝试过的想法。

    1. 使用 Core Text直接地。其他 API 都建立在它之上。

    2. 并行化。所有现代 Mac(甚至所有现代 iOS 设备)都有多个内核。将字符串数组分成几个子数组。对于每个子数组,将一个 block 提交到 global GCD queue .在 block 中,创建必要的 Core Text 或 NSLayoutManager 对象并测量子数组中的字符串。可以通过这种方式安全地使用这两个 API。 (Core Text) (NSLayoutManager)

    3. 关于“高内存占用”:Use Local Autorelease Pool Blocks to Reduce Peak Memory Footprint.

    4. 关于“所有时间都花在创建上述字符串的过程中,这本身就是一个破坏因素”:您是说所有时间都花在这些行上:

      double random = (double)arc4random_uniform(1000) / 1000;
      NSString *randomNumber = [NSString stringWithFormat:@"%f", random];

      格式化一个 float 是很昂贵的。这是您的真实用例吗?如果您只想为 0 ≤ n < 1000 格式化 n/1000 形式的随机有理数,则有更快的方法。此外,在许多字体中,所有数字都具有相同的宽度,因此很容易排版数字列。如果你选择这样的字体,你可以避免首先测量字符串。

    更新

    这是我使用 Core Text 编写的最快的代码。在我的 Core i7 MacBook Pro 上,调度版本的速度几乎是单线程版本的两倍。我的项目分支是 here .

    static CGFloat maxWidthOfStringsUsingCTFramesetter(
    NSArray *strings, NSRange range) {
    NSString *bigString =
    [[strings subarrayWithRange:range] componentsJoinedByString:@"\n"];
    NSAttributedString *richText =
    [[NSAttributedString alloc]
    initWithString:bigString
    attributes:@{ NSFontAttributeName: (__bridge NSFont *)font }];
    CGPathRef path =
    CGPathCreateWithRect(CGRectMake(0, 0, CGFLOAT_MAX, CGFLOAT_MAX), NULL);
    CGFloat width = 0.0;
    CTFramesetterRef setter =
    CTFramesetterCreateWithAttributedString(
    (__bridge CFAttributedStringRef)richText);
    CTFrameRef frame =
    CTFramesetterCreateFrame(
    setter, CFRangeMake(0, bigString.length), path, NULL);
    NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
    for (id item in lines) {
    CTLineRef line = (__bridge CTLineRef)item;
    width = MAX(width, CTLineGetTypographicBounds(line, NULL, NULL, NULL));
    }
    CFRelease(frame);
    CFRelease(setter);
    CFRelease(path);
    return (CGFloat)width;
    }

    static void test_CTFramesetter() {
    runTest(__func__, ^{
    return maxWidthOfStringsUsingCTFramesetter(
    testStrings, NSMakeRange(0, testStrings.count));
    });
    }

    static void test_CTFramesetter_dispatched() {
    runTest(__func__, ^{
    dispatch_queue_t gatherQueue = dispatch_queue_create(
    "test_CTFramesetter_dispatched result-gathering queue", nil);
    dispatch_queue_t runQueue =
    dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
    dispatch_group_t group = dispatch_group_create();

    __block CGFloat gatheredWidth = 0.0;

    const size_t Parallelism = 16;
    const size_t totalCount = testStrings.count;
    // Force unsigned long to get 64-bit math to avoid overflow for
    // large totalCounts.
    for (unsigned long i = 0; i < Parallelism; ++i) {
    NSUInteger start = (totalCount * i) / Parallelism;
    NSUInteger end = (totalCount * (i + 1)) / Parallelism;
    NSRange range = NSMakeRange(start, end - start);
    dispatch_group_async(group, runQueue, ^{
    double width =
    maxWidthOfStringsUsingCTFramesetter(testStrings, range);
    dispatch_sync(gatherQueue, ^{
    gatheredWidth = MAX(gatheredWidth, width);
    });
    });
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    return gatheredWidth;
    });
    }

    关于objective-c - 在 AppKit 中测量文本宽度的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30537811/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com