1

.m ファイルで宣言されたグローバル NSString 変数があります。stringWithFormat を使用して .m ファイル内の任意の場所に文字列値を指定すると、その値は関数呼び出し間で保持されません。ただし、stringWithString を使用して同じことを行うと、値は実装全体で持続し、すべての関数が呼び出されるため、真のグローバルな動作が得られます。言い換えれば、メモリ管理は stringWithFormat と stringWithString で内部的にどのように異なるのでしょうか?

「割り当て解除されたインスタンスに送信されたメッセージ」をスローしている間、stringWithString の値が保持されるのはなぜですか (NSString のその後の使用では、stringWithFormat を使用して NSString に値を与えた関数の後に来る別の関数の NSLog ステートメントで言います) stringWithFormat を使用する場合? 同じものをstringWithStringに置き換えても、そのような問題はありません。

ありがとう!

編集:後で手動で保持したときに、stringWithFormatの場合にYESが機能したことを忘れていました。値が持続しました。したがって、質問です。

4

2 に答える 2

3

文字列を保持していないようです。このため、後でアクセスしようとすると、割り当てが解除されています。メモリ管理に慣れていない場合は、Appleのメモリ管理プログラミング ガイドを参照してください。

-stringWithString:壊れない理由は、コンパイラが文字列リテラルで何らかの最適化を行っているためと考えられます。プログラムを調べて、定義されている同一の文字列への参照を 1 つだけ格納します。このため、ポインターはアプリの有効期間を通じて有効なままになります。

これに頼るべきではありません。すべてのコンパイラがこの最適化を行うことを保証することはできません。作成時に変数を保持し、必要がなくなったら解放します。

于 2011-02-22T12:04:11.180 に答える
2

コンパイラは賢く、すべてが同じ値を保持する多数の異なる NSString インスタンスを作成する代わりに、解放できない 1 つのインスタンスを作成し、他のすべてのインスタンスはプログラムでハードコードされた NSString を指すだけです。

また、ハードコードされた NSString の割り当てが解除されることはないため、自動解放プールによって割り当てが解除された後でも使用できます。

これは、間違ったメモリ管理をカバーするだけです。そして、あなたは絶対にこの振る舞いに頼るべきではありません.


編集。これ以上言うことはありません。stringWithString:literal で作成した NSString は、単にメモリ内のリテラルの場所を指します。

ちょっとした例:

NSString *string = @"Foo";
NSLog(@"%@ - %p", string, string);
NSString *string2 = string;
NSLog(@"%@ - %p", string2, string2);
NSString *string3 = [string copy];
NSLog(@"%@ - %p", string3, string3);
NSString *string4 = [string retain];
NSLog(@"%@ - %p", string4, string4);
NSString *string5 = [NSString stringWithString:string];
NSLog(@"%@ - %p", string5, string5);
NSString *string6 = [[NSString alloc] initWithString:string];
NSLog(@"%@ - %p", string6, string6);

それらはすべて同じアドレスを指していることがわかります。

2011-02-22 13:24:41.202 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.207 xxx[40783:207] Foo - 0x74120

そして、それらすべてが割り当て解除されることはありません。したがって、コード内の他のメソッドから string5 にアクセスすることができ、それは依然としてアドレス 295740 を指し、NSString "Foo" は依然として存在します。

ただし、文字列リテラルを指していない NSString オブジェクトはこの時点で割り当て解除され、不正なアクセス例外が発生します。

メモリ管理規則に違反していますが、文字列リテラルのみを使用している場合は気付かないでしょう。コンパイラの動作が変わるまで。

したがって、正しく行い、適切なメモリ管理を学び、内部に依存しないでください。後で必要になった場合に備えて、自動解放されたすべてのオブジェクトを保持します。文字列リテラルを指している場合でも

于 2011-02-22T12:04:00.330 に答える