the method enumerateAttributesInRange gets a block of code and executes it for every attribute in NSAttributedString
- Does it call the bock asynchronously?
When The following method gets called twice in a row really quick 1 after the othr my app gets frozen, I am wondering of it’s because enumerateAttributesInRange runs the block of code asynchronously, so 2 threads are trying to modify my AttributedString at the same time.
- (void) doSomething
{
//following line works fine
[self doSomethingwithAttributedString];
//following line works fine
[self doSomethingwithAttributedString];
[self performSelector:@selector(doSomethingwithAttributedString) withObject:nil afterDelay:1];
//following crashes
[self doSomethingwithAttributedString];
[self doSomethingwithAttributedString];
}
- (void)doSomethingwithAttributedString
{
[self.attributedString enumerateAttributesInRange:_selectedRange options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:
^(NSDictionary *attributes, NSRange range, BOOL *stop) {
// Here I modify the dictionary and add it back to my attributedString
}];
}
You are modifying the attributed string while it is being enumerated. I bet this thoroughly confuses the enumerator, since the attributed string it is working on is not in the state it was in when it started enumerating. In the block, only collect the attributes, e.g. in a dictionary or array, but modify them and apply them to the string afterward, i.e. after the enumeration is finished.
In other words: don’t put code that modifies the attributed string inside the block that is called during enumeration. The docs say you can modify the attributed string inside the range on which the block applies, but ISTM you must take enormous care not to go outside. I wouldn’t do this.