mattt/TTTAttributedLabel — pull request #166 by pashields (2013-02-01 17:15:37+00:00)
Title: Move final text check to main thread when using data detectors. Fixes #162

The bug is caused by the main thread altering the text of the label after the data detection. Previously, we would check that the text used as input to the data detector was the same as the label text immediately after detection. This works as long as the main thread doesn't change the text between this check and the execution of the block within the dispatch_sync. It seems like this shouldn't be a big deal, but in practice can cause crashing. The resulting code is slightly uglier, but it splits the existing if in two, such that we still only dispatch to the main thread if there are results. Once on the main thread, we compare the text used to generate the results with the current text of the label before apply the detected links.

Since the check has been moved onto the main thread, I see no reason why that dispatch should be sync, so I have changed that to an async. There might be some good reasons to leave that as sync, I just couldn't think of any.

If you'd like to confirm the bug, you can use the following patch:

```
diff --git a/Example/AttributedTableViewCell.m b/Example/AttributedTableViewCell.m
index 53b083d..9dae06d 100644
--- a/Example/AttributedTableViewCell.m
+++ b/Example/AttributedTableViewCell.m
@@ -67,6 +67,7 @@ static inline NSRegularExpression * ParenthesisRegularExpression() {
self.summaryLabel.lineBreakMode = UILineBreakModeWordWrap;
self.summaryLabel.numberOfLines = 0;
self.summaryLabel.linkAttributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCTUnderlineStyleAttributeName];
+ self.summaryLabel.dataDetectorTypes = UIDataDetectorTypeAll;

NSMutableDictionary *mutableActiveLinkAttributes = [NSMutableDictionary dictionary];
[mutableActiveLinkAttributes setValue:(id)[[UIColor redColor] CGColor] forKey:(NSString *)kCTForegroundColorAttributeName];
@@ -130,6 +131,17 @@ static inline NSRegularExpression * ParenthesisRegularExpression() {
NSRange linkRange = [regexp rangeOfFirstMatchInString:self.summaryText options:0 range:NSMakeRange(0, [self.summaryText length])];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://en.wikipedia.org/wiki/%@", [self.summaryText substringWithRange:linkRange]]];
[self.summaryLabel addLinkToURL:url withRange:linkRange];
+
+ [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(textify) userInfo:nil repeats:YES];
+}
+
+- (void)textify
+{
+ if (rand() % 2 == 0) {
+ [self setSummaryText:@"foo"];
+ } else {
+ [self setSummaryText:@"http://www.google.com"];
+ }
}

+ (CGFloat)heightForCellWithText:(NSString *)text {
```

This is a pathological case and will max out your CPU when you run it, so beware. It should cause the crash when this pull request is not applied.

Thanks!