我还没有进行任何性能测试,但我认为在这里你可以得到最好的。请注意,您可以通过使用更简单的字符串连接(参见 end)而不是 stringWithFormat 来加快速度。我保留了这些以使其更接近您的原始示例。
它代表了您的代码的相当重的工作
- 通过使用块避免对每个键进行字典查找,因此字典可以做最佳的事情来一次返回键和值
- 使用预先分配的缓冲区(估计)构建字符串,然后一次性添加所有属性
- 使用
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;
}