1

我已经确定操作 anNSMutableAttributedString是我的应用程序的瓶颈。我可以做些什么来加快构建我NSMutableAttributedString的 s?例如,是否有与 Java 等价的东西StringBuilder

appendFormat是最大的罪魁祸首。

编辑:示例,根据要求。在某些情况下,我绝对可以使用直接连接。我不知道那更快。

NSMutableAttributedString *result = [NSMutableAttributedString new];
for (NSString *key in [dict allKeys]) {
    [[result mutableString] appendFormat:@"%@=", dataKey];
    NSRange tempRange = NSMakeRange([result length] - [key length], [key length]);
    [result addAttributes:defaultKeyAttributes range:tempRange];

    [[result mutableString] appendFormat:@"%@;", [dict objectForKey:key]];
}
4

1 回答 1

1

我还没有进行任何性能测试,但我认为在这里你可以得到最好的。请注意,您可以通过使用更简单的字符串连接(参见 end)而不是 stringWithFormat 来加快速度。我保留了这些以使其更接近您的原始示例。

它代表了您的代码的相当重的工作

  1. 通过使用块避免对每个键进行字典查找,因此字典可以做最佳的事情来一次返回键和值
  2. 使用预先分配的缓冲区(估计)构建字符串,然后一次性添加所有属性
  3. 使用setAttributes而不是addAttributes作为给定范围的初始设置,而不是附加(可能更有效)。

与您的代码段一样进行转换的函数:

NSMutableAttributedString* buildAttributedStringFromDict(NSDictionary* dict, NSDictionary* defaultKeyAttributes)
{
  NSUInteger numPairs = [dict count];
  NSUInteger guessInitialCapacity = numPairs * 20;  // use a multiplier based on your domain to avoid string expansions
  NSMutableString* builder = [NSMutableString stringWithCapacity:guessInitialCapacity];
  NSRange ranges[numPairs];
  NSRange* rp = ranges;  // use pointer to refer to C array because compiler won't let us put __block on it
  __block NSUInteger rangeIndex = 0;
  // loop building one big string and noting ranges, using optimal iteration letting dictionary feed us matching key and value
  [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop){
    NSString* formattedKey = [NSString stringWithFormat:@"%@=", key];
    [builder appendString:formattedKey];
    NSUInteger keylen = [formattedKey length];  // allows for anything that happens in the format
    rp[rangeIndex].length = keylen;
    rp[rangeIndex].location = [builder length] - keylen;
    ++rangeIndex;
    [builder appendFormat:@"%@;", obj];
  }];

  // convert built string into one we can add attributes to
  NSMutableAttributedString *result = [[NSMutableAttributedString alloc] initWithString:builder];
  // loop adding attributes for the key areas;
  for(rangeIndex = 0; rangeIndex < numPairs; ++rangeIndex)
  {
    [result setAttributes:defaultKeyAttributes range:ranges[rangeIndex]];
  }
  return result;
}

以字典文字调用代码为例:

id test = buildAttributedStringFromDict(
  @{  @"Name":@"Andy",
      @"Role":@"Boss"},
  @{  NSForegroundColorAttributeName:[UIColor redColor],
      NSFontAttributeName:[UIFont fontWithName:@"Papyrus" size:14.0]}
);

调试控制台输出:

Printing description of test:
Name={
    NSColor = "UIDeviceRGBColorSpace 1 0 0 1";
    NSFont = "<UICFFont: 0x767ed50> font-family: \"Papyrus\"; font-weight: normal; font-style: normal; font-size: 14px";
}Andy;{
}Role={
    NSColor = "UIDeviceRGBColorSpace 1 0 0 1";
    NSFont = "<UICFFont: 0x767ed50> font-family: \"Papyrus\"; font-weight: normal; font-style: normal; font-size: 14px";
}Boss;{
}

更新 - 这是一个使用简单连接的重写函数

NSMutableAttributedString* buildAttributedStringFromDict(NSDictionary* dict, NSDictionary* defaultKeyAttributes)
{
  NSUInteger numPairs = [dict count];
  NSUInteger guessInitialCapacity = numPairs * 20;  // use a multiplier based on your domain to avoid string expansions
  NSMutableString* builder = [NSMutableString stringWithCapacity:guessInitialCapacity];
  NSRange ranges[numPairs];
  NSRange* rp = ranges;  // use pointer to refer to C array because compiler won't let us put __block on it
  __block NSUInteger rangeIndex = 0;
  // loop building one big string and noting ranges, using optimal iteration letting dictionary feed us matching key and value
  [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop){
    [builder appendString:key];
    [builder appendString:@"="];
    NSUInteger keylen = [key length] + 1; // add 1 for = sign
    rp[rangeIndex].length = keylen;
    rp[rangeIndex].location = [builder length] - keylen;
    ++rangeIndex;
    [builder appendString:obj];
    [builder appendString:@";"];
  }];

  // convert built string into one we can add attributes to
  NSMutableAttributedString *result = [[NSMutableAttributedString alloc] initWithString:builder];
  // loop adding attributes for the key areas;
  for(rangeIndex = 0; rangeIndex < numPairs; ++rangeIndex)
  {
    [result setAttributes:defaultKeyAttributes range:ranges[rangeIndex]];
  }
  return result;
}
于 2013-09-11T07:40:46.363 回答