I'm calling the following selector on an existing NSAttributedString
with no kCTFontAttributeName
ranges:
[attributedString enumerateAttribute:(NSString *) kCTFontAttributeName
inRange:NSMakeRange(0, [attributedString length])
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:^(id value, NSRange range, BOOL *stop) {
NSLog(@"Attribute: %@, %@", value, NSStringFromRange(range));
}];
and I get the output below, but I would expect to get no output. Suggestions?
Attribute: (null), {0, 27}
Attribute: (null), {27, 1}
Attribute: (null), {28, 1}
Attribute: (null), {29, 1}
Attribute: (null), {30, 1}
The short answer? -enumerateAttribute:inRange:options:usingBlock:
doesn't do what you (or I, originally) thought it does.
From the name, you might assume it only enumerates over ranges of the receiver that contain the given attribute. This is not the case. It always enumerates over the entire string. It calls the block for each run it encounters. The value
passed into the block is set to the value the given attribute for that run. If the current run doesn't contain the given attribute, it passes nil
for value
.
Thus, for a string that does not contain the given attribute, it will still fire the block, but the value
will always be nil
. For a string that that is completely covered by the the given attribute (with the same value), you would expect the block to fire once with value
being equal to that attribute's value in the string. For a string that is partially covered by the given attribute, you would expect the block to fire multiple times, sometimes with a value
of nil
, and sometimes with a value
equal to that of the attribute.
Hope that helps. It took me a while to look at it from the correct direction, also.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With