2011-10-01 11 views
8

私は以下のコードを持っています。私は時折SIGSEGVを取得します。私はブロックを使ってメモリ管理に関する何かが欠けていると感じています。このブロックにオートレリースされたreplacedUrlsを渡すことは安全ですか?インスタンス変数formattedTextの変更はどうでしょうか?ブロックを使用しているSIGSEGVの原因は何ですか?

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

読んだ後、私は自分自身が保持されるので、私が保持サイクルをどこに作るのか確かに見ています。しかし、それが実際の問題をどのように作り出すかはまだ分かりません。 – tjg184

+0

dodgiest行は 'if(error){return;}ですが、どのように問題が発生するのかわかりません(この時点でコードを返すと正常に回復します)。自己保持は必ずしも保持サイクルを引き起こすとは限らず、保持サイクルはSIGSEGVを引き起こさない。 – hooleyhoop

+0

ええ、その行は奇妙です。私はそれが必要であるかどうかも分かりません。私はそれを健全性チェックとして追加したと思う。その行を追加する前に、SIGSEGVを取得していました。これらのif文のほとんどは、クラッシュレポートが特定の行ではなく一般的なブロックを指しているため追加されました。問題を追跡するのに迷惑を掛けます。これでformattedTextを変更するのは安全ですか? – tjg184

答えて

2

メモリ管理に関連する問題が発生しているようです。まず文字列self.formattedTextを検索します。これは、この検索が行われている間、あなたのNSDataDetectorインスタンスはおそらく文字などを読むために文字列にアクセスする必要があることを意味します。self.formattedTextが割り当て解除されない限り、これはすべてうまく動作します。通常、このようなブロックメソッドの場合でも、関数呼び出しが終了するまで引数を保持するのは呼び出し元の責任です。

一致するブロック内でself.formattedTextの値を変更すると、古い値が自動的に解放されます(これはretainプロパティと仮定します)。私は、NSDataDetectorが行うかもしれないキャッシング、または自動解放プールなどに関する問題を認識していませんが、これが問題を引き起こす可能性はかなりあります。

私の提案は、あなたではなく、プレーンself.formattedTextよりも、enumerateMatchesInString:引数として[NSString stringWithString:self.formattedText]を渡すことです。このようにして、NSDataDetectorには、自動解放プールがなくなるまで解放されないインスタンスが渡されます。

+0

私はこれを完全にテストしていませんが、あなたの答えは価値があると思います。 :) – tjg184

関連する問題