Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective C - Change all attributes in NSAttributedString?

[attributedString enumerateAttributesInRange:range options:NSAttributedStringEnumerationReverse usingBlock:
     ^(NSDictionary *attributes, NSRange range, BOOL *stop) {

         NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
         [mutableAttributes setObject:[NSNumber numberWithInt:1] forKey:@"NSUnderline"];
         attributes = mutableAttributes;

     }];

I am trying to loop through all attributed and add NSUnderline to them. when debugging it seems like NSUnderline is added to the dictionary, but when i loop for the second time they are removed. Am I doing anything wrong while updating NSDictionaries?

like image 506
aryaxt Avatar asked Jul 21 '11 20:07

aryaxt


2 Answers

Jonathan's answer does a good job of explaining why it doesn't work. To make it work, you need to tell the attributed string to use these new attributes.

[attributedString enumerateAttributesInRange:range options:NSAttributedStringEnumerationReverse usingBlock:
     ^(NSDictionary *attributes, NSRange range, BOOL *stop) {

         NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
         [mutableAttributes setObject:[NSNumber numberWithInt:1] forKey:@"NSUnderline"];
         [attributedString setAttributes:mutableAttributes range:range];

 }];

Changing the attributes of an attributed string requires that it is a NSMutableAttributedString.

There is also an easier way to do this. NSMutableAttributedString defines the addAttribute:value:range: method, which sets the value of a specific attribute over the specified range, without changing other attributes. You can replace your code with a simple call to this method (still requiring a mutable string).

[attributedString addAttribute:@"NSUnderline" value:[NSNumber numberWithInt:1] range:(NSRange){0,[attributedString length]}];
like image 189
ughoavgfhw Avatar answered Nov 15 '22 21:11

ughoavgfhw


You're modifying a local copy of the dictionary; the attributed string does not have any way to see the change.

Pointers in C are passed by value (and thus what they point to is passed by reference.) So when you assign a new value to attributes, the code that called the block has no idea you changed it. The change does not propagate outside of the block's scope.

like image 25
Jonathan Grynspan Avatar answered Nov 15 '22 21:11

Jonathan Grynspan