2011-10-01 17 views
8

Tengo el siguiente código. Obtengo un SIGSEGV de vez en cuando. Tengo la sensación de que me falta algo sobre el manejo de la memoria usando bloques. ¿Es seguro pasar los Urs reemplazados, que se liberan automáticamente a este bloque? ¿Qué hay de modificar la variable de instancia formattedText?¿Qué está causando que un SIGSEGV use bloques?

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 
      } 
     }]; 
+0

Después de leerlo, definitivamente estoy viendo dónde estaría creando un ciclo de retención ya que el yo se retendría. Sin embargo, aún no estoy seguro de cómo eso crearía el problema real. – tjg184

+0

la línea más difícil es 'if (error) {return;} pero tampoco estoy seguro de cómo eso causa su problema (su código se recupera con gracia si regresa en este momento, ¿no?). Retener uno mismo no necesariamente causa un ciclo de retención, y un ciclo de retención no causaría un SIGSEGV; – hooleyhoop

+0

Sí, esa línea es extraña. Ni siquiera estoy seguro de que sea necesario. Creo que lo agregué como un control de cordura. Estaba obteniendo un SIGSEGV antes de agregar esa línea. La mayoría de esas declaraciones se agregaron porque el informe de fallos solo apuntaba al bloque general y no a una línea específica. Es un poco molesto rastrear el problema. ¿Es seguro modificar el texto formateado en esto? – tjg184

Respuesta

2

Parece que el problema que está experimentando está relacionado con la gestión de la memoria. Comienza buscando a través de la cadena self.formattedText. Esto significa que, mientras se realiza esta búsqueda, su instancia NSDataDetector probablemente necesite acceder a la cadena para leer caracteres, etc. Esto funciona todo bien y bien, siempre que self.formattedText no sea desasignado. Usualmente, incluso para métodos de bloqueo como este, es responsabilidad del que llama retener los argumentos hasta el final de la llamada a la función.

Cuando, dentro de su bloque encontrado coincide, cambia el valor de self.formattedText, el valor anterior se libera automáticamente (suponiendo que se trata de una propiedad retain). No conozco el almacenamiento en caché que podría hacer NSDataDetector ni los problemas relacionados con los grupos de liberación automática, etc., pero estoy bastante seguro de que esto podría causar un problema.

mi sugerencia es que se pasa[NSString stringWithString:self.formattedText] como argumento enumerateMatchesInString:, en lugar de la llanura self.formattedText. De esta forma, le pasa al NSDataDetector una instancia que no se liberará hasta que se vacíe el grupo de autorrelease.

+0

No he probado completamente esto, pero creo que su respuesta es válida. :) – tjg184

Cuestiones relacionadas