3

大きな文字列を連結すると、EXEC_BAD_ACCESS が発生します。

フィードから読み取り、webview を作成するために、次のように文字列を作成します。

NSString *pageData = @"<h1>header</h1>";

pageData = [pageData stringByAppendingFormat@"<p>"];
pageData = [pageData stringByAppendingFormat@"self.bodyText"];
pageData = [pageData stringByAppendingFormat@"</p>"];
etc

私が抱えている問題は、単語を数えるとき、self.bodytextがスペースを含む21,089文字であることです。これを行うためのより良い方法はありますか?

ありがとう

4

4 に答える 4

6

次のような場合は、 NSMutableStringを使用することをお勧めします。

NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

[pageData appendFormat:@"<h1>header</h1>"];
[pageData appendFormat:@"<p>"];
...

NSMutableStringこの種の順次連結用に設計されており、基本的な NSString クラスは実際にはこの方法で使用することを意図していません。元のコードでは、 を呼び出すたびに新しい NSString を実際に割り当ててstringByAppendFormat:から、既に追加した数千の文字をすべてその中にコピーします。呼び出しを追加すると一時文字列のサイズが指数関数的に増加するため、メモリ不足エラーが発生しやすくなります。

NSMutableString を使用するとappendFormat:、 を呼び出すときにすべての文字列データが再コピーされるわけではありません。これは、変更可能な文字列が内部バッファーを維持し、新しい文字列をその末尾に追加するだけだからです。文字列のサイズによっては、事前に大量のメモリを確保しておく必要がある場合があります (...WithCapacity:引数には意味のある数値を使用してください)。ただし、実際にパフォーマンスの問題が発生しない限り、その方法を使用する必要はありません。

于 2010-05-04T16:10:37.160 に答える
2

サンプル コードにはいくつかの問題があります。

  1. 複数の部分を追加して出力文字列を作成するには、NSMutableString を使用する必要があります。NSString は不変クラスです。つまり、呼び出すたびstringByAppendingFormat:に、自動解放プールによって収集および解放する必要がある追加の新しい NSString オブジェクトを作成するオーバーヘッドが発生します。

    NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

  2. またはの代わりにappendString:onを使用してNSMutableString、コンテンツを追加する必要があります。フォーマット メソッドは、プレースホルダーとして特別なフィールドを含むフォーマット指定子に基づいて新しい文字列を作成するためのものです。詳細については、文字列オブジェクトのフォーマットを参照してください。コードのようにリテラル文字列だけを使用している場合、存在しないプレースホルダーの文字列を解析するオーバーヘッドが発生します。さらに重要なのは、文字列にプレースホルダー (またはプレースホルダーのようなもの) がある場合です。 )その中で、あなたが得ているクラッシュで終わります。これは、bodyText が追加されたときに発生する可能性が最も高いです。したがって、単に ' を追加したい場合stringByAppendingFormat:appendFormat:stringByAppendingFormat:EXEC_BAD_ACCESS

    '次のNSMutableStringようなことを行います。

    [pageData appendString:@"<p>"];

  3. プロパティの内容を文字列に追加したい場合は、self.bodyTextプロパティの名前を文字列リテラル内に入れるべきではありません (つまり、@"self.bodyText" はリテラル文字列 "self.bodyText" であり、内容ではありません)。試してみてください:

    [pageData appendString:self.bodyText];

たとえば、次の形式指定を使用して、サンプル コードの 3 行すべてを実際に組み合わせることができます。

pageData = [pageData stringByAppendingFormat:@"<p>%@</p>", self.bodyText];

フォーマット仕様には、またはメッセージをオブジェクト%@に送信した結果を挿入することを意味するプレースホルダーが あります。の場合、this は単純に文字列の内容です。descriptiondescriptionWithLocale:NSString

于 2010-05-04T20:07:24.130 に答える
1

任意の文字列を処理する場合は、appendFormat:の代わりにappendString:を使用してください。

pageData = [pageData stringByAppendingString:@"<p>"];
pageData = [pageData stringByAppendingString:@"self.bodyText"];
pageData = [pageData stringByAppendingString:@"</p>"];

または、形式として任意の文字列を使用しないでください。

pageData = [pageData stringByAppendingFormat:@"<p>%@</p>" , @"self.bodyText"];

文字列を分割して構築する場合は、複数のstringBy呼び出しの代わりにNSMutableStringを使用してください。

%はフォーマットされた文字列とURLエスケープの特殊文字であるため、bodyTextにURLが含まれていると、簡単にクラッシュする可能性があることに注意してください。

于 2010-05-04T18:51:34.223 に答える
1

文字列の長さが本当に問題だとは思いません。50,000 文字の文字列は約 100 KB しかありません。ただし、フォーマット文字列の使用には細心の注意を払う必要があります。文字列に書式指定子のようなものが含まれている場合は、対応する引数が必要です。そうしないと、運が良ければガベージが発生し、そうでなければクラッシュします。あなたの説明から他に明らかな問題がないので、これがエラーだと思います。そこに入力する内容に注意し、動的テキストをフォーマット文字列に入れないようにして%@ください。フォーマット文字列に a を入力し、動的テキストを引数として渡すだけです。

于 2010-05-04T18:43:46.930 に答える