Что вызывает SIGSEGV с использованием блоков? - PullRequest
8 голосов
/ 01 октября 2011

У меня есть следующий код. Я иногда получаю SIGSEGV. У меня такое ощущение, что я что-то упускаю в отношении управления памятью с помощью блоков. Безопасно ли передавать замененные URL-адреса, которые автоматически высвобождаются в этот блок? Как насчет изменения переменной экземпляра formattedText?

    NSMutableSet* replacedUrls = [[[NSMutableSet alloc] init] autorelease];

    NSError *error = nil; 
    NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:
                                (NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber)
                                                               error:&error];
    if (error) {
        return;
    }

    [detector enumerateMatchesInString:self.formattedText 
              options:0 
              range:NSMakeRange(0, [self.formattedText length]) 
              usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

            @try  {
                if (result.resultType == NSTextCheckingTypePhoneNumber) {

                    if (!result.phoneNumber) {
                        // not sure if this is possible
                        return;
                    }

                    self.formattedText = [self.formattedText stringByReplacingOccurrencesOfString:result.phoneNumber
                                                                                       withString:[NSString stringWithFormat:@"<a href=\"tel://%@\">%@</a>", result.phoneNumber, result.phoneNumber]];
                }
                else if (result.resultType == NSTextCheckingTypeLink) {

                    if (!result.URL) {
                        // not sure if this is possible
                        return;
                    }

                    NSString* fullUrl = [result.URL absoluteString];

                    if (!fullUrl) {
                        return; 
                    }

                    if ([replacedUrls containsObject:fullUrl]) {
                        return; 
                    }

                    // not sure if this is possible
                    if ([result.URL host] && [result.URL path]) {
                        NSString* urlWithNoScheme = [NSString stringWithFormat:@"%@%@", [result.URL host], [result.URL path]];

                        // replace all http://www.google.com to www.google.com
                        self.formattedText = [self.formattedText stringByReplacingOccurrencesOfString:fullUrl
                                                                                           withString:urlWithNoScheme];

                        // replace all www.google.com with http://www.google.com
                        NSString* replaceText = [NSString stringWithFormat:@"<a href=\"%@\">%@</a>", fullUrl, fullUrl];
                        self.formattedText = [self.formattedText stringByReplacingOccurrencesOfString:urlWithNoScheme
                                                                                           withString:replaceText];

                        [replacedUrls addObject:fullUrl];
                    }
                }
            }
            @catch (NSException* ignore) {
                // ignore any issues
            }
        }];

1 Ответ

2 голосов
/ 15 октября 2011

Кажется, что проблема, с которой вы столкнулись, связана с управлением памятью. Вы начинаете с поиска по строке self.formattedText. Это означает, что во время этого поиска вашему экземпляру NSDataDetector, вероятно, необходим доступ к строке для чтения символов и т. Д. Это работает отлично и хорошо, пока self.formattedText не освобождается. Обычно, даже для блочных методов, подобных этому, вызывающая сторона несет ответственность за сохранение аргументов до конца вызова функции.

Когда внутри вашего найденного совпадения блока вы меняете значение self.formattedText, старое значение автоматически освобождается (при условии, что это свойство retain). Мне неизвестно о кешировании, которое может выполнять NSDataDetector, или о проблемах, связанных с пулами автоматического выпуска и т. Д., Но я почти уверен, что это может вызвать проблему.

Я предлагаю вам передать [NSString stringWithString:self.formattedText] в качестве аргумента enumerateMatchesInString: вместо простого self.formattedText. Таким образом, вы передаете NSDataDetector экземпляр, который не будет освобожден до тех пор, пока не будет очищен пул автоматического выпуска.

...