2

私は客観的な c をほぼ 1 週間使用しており、主に c++ コーダーです。Apple のメモリ管理ガイドを読んだ後、C++ でのメモリ使用スタイルを目的の C に持ち込もうとしました... これらのシナリオを結論付けようとしました。これらの手順に従えば、メモリの間違いはないと思います。私が間違っている場合は、親切にお知らせください:)

個人的に言えば、自動解放を使用しないようにします。自動解放を使用すると、特定の自動解放プールが空になる前に、常に冗長なメモリが存在する可能性があります。release のみを使用します。これにより、アプリケーションが常に最小限のメモリを使用するようになります。

Apple が言うもう 1 つのことは、私自身の言葉で説明すると、次のとおりです。retain/alloc/copy を追加するたびに、どこかにリリースを追加する必要があります。

私が結論付けるすべてのシナリオは次のとおりです。

  1. 同じ関数内:オブジェクトの割り当て、使用および解放

  2. クラスのinit関数でオブジェクトを割り当て、クラスのdealloc関数でオブジェクトを解放する

  3. ポインターを所有する必要がある場合は、クラスのメソッド (メソッド Aとしましょう) で入力ポインターを保持し、クラスのdealloc関数でポインターを解放する必要があります。

    客観的なcでretainを使用するタイミングは、c/c++でmemcpyを使用するタイミングと同じであることがわかったので、 retainを「メモリ効率の良いコピー」と見なします

    入力保持ポインターがメンバーポインター変数に設定される場合は、最初にメンバーポインターを解放する必要があります。したがって、case[3] では、クラスのinitのallocメソッド Aのreleaseと対になり、メソッド A保持deallocのreleaseと対になります。

  4. 戻り値としてポインタを返します。正直なところ、C++ を使用するときは、そのようなことは決してしません。メンバー ポインターを返す場合は問題ありません。誰かが面倒を見てくれます:

    -(UIButton*) getTheButton() {
        return theButton;
    }
    

    しかし、ローカルに割り当てられたオブジェクトへのポインターを返すのは本当にひどいことです。

    -(UIButton*) getTheButton() {
        UIButton* myButton = [[UIButton alloc] init];
        return myButton; //TERRIBLE!
    } 
    

    その場合は autorelease を使用する必要があると言う人もいるかもしれませんが、これを使用してそのソリューションをバイパスしたいだけです: メンバー ポインターのみを返すか、ポインターを返さないか、指定された入力ポインターのみを操作します。

    -void operateOnTheButton(UIButton* button) {
        [button release];
        button = [[UIButton alloc] init];
    } 
    

したがって、上記のメモリ使用方法に従って問題が発生した場合は、お知らせください。

ありがとう

4

5 に答える 5

9

を使用する必要がある重要なシナリオが1つありますautorelease。オブジェクトを割り当て/保持/コピーしてから、そのオブジェクトを所有releaseしている他のコードに返す場合、他のコードがそれを使用する必要があるため(または返さなかった場合)、オブジェクトを返すことはできません。

この状況では、オブジェクトにメッセージを送信してオブジェクトの解放に責任を負わなければなりません。これにより、オブジェクトが最終的に解放されるようになります。autoreleaseこれはまさにNSStringのような基礎メソッドがstringWithString:行うことです。このメソッドから取得しreleaseた文字列オブジェクトは、割り当て/保持/コピーしなかったため、必要ありませんが、メソッドが自動解放しなかった場合は、存続し[pool drain]てメモリリークになります。

参照カウントがどのように機能するかを理解してください。releaseオブジェクトの参照カウントをデクリメントします。カウントが0に達すると、オブジェクトは破棄されます。alloc参照カウントが1のオブジェクトをcopy作成します。retain受信オブジェクトの参照カウントを1ずつインクリメントします。割り当て/保持/コピーごとに1つ必要releaseです。1つ上、1つ下。

したがって、作成したオブジェクトを返して、呼び出し先に制御を渡すと、1対1の方程式のバランスが崩れます。これは、そのオブジェクトにアクセスする方法がないためですrelease。だからautoreleaseです。受信者の参照カウンターをデクリメントしないので、破壊される危険はありませんが、プールが空になると、プール内の各オブジェクトは、受信したreleaseメッセージごとautoreleaseに1つのメッセージを受け取り、バランスを復元します(オブジェクトが意図的に保持されていない限り)それはドレインを生き残るでしょう、その場合、呼び出し先はrelease後でそれをする必要があります)。

ポイント4に関しては、2番目の例は問題ありませんautorelease。基礎クラスには、この手法の例がたくさんあります。NSString、NSArray、NSDictionaryなどのすべてのデータクラスには、ローカルに割り当てられたオブジェクトポインタを返すメソッドがあります。それらは通常、またはthisWiththat:のような形式を持っています。後者は辞書オブジェクトを割り当て、ファイルの内容を入力し、自動解放して、ポインタを返します。これはファクトリ関数と呼ばれます。obj-c、javaでも非常に一般的なパターン。stringWithstring:dictionaryWithContentsOfFile:

3番目のコード例では、後でランタイムエラーが発生します。所有していないオブジェクトをリリースしています。所有者はあなたにreleaseそれを期待しません。これは、受信するメッセージが多すぎreleaseて、ランタイムエラーが発生する可能性があることを意味します。割り当て/保持/コピーしなかった場合は、所有していないため、解放しないでください。

于 2010-07-23T02:51:52.610 に答える
2

自動解放部分が正しくありません。alloc / reserved/copyで始まらないファクトリメソッドを実行する場合。自動リリースする必要があります。呼び出し元はオブジェクトを作成しないため、呼び出し元はオブジェクトを解放できず、解放しないでください。したがって、呼び出し元が何かを実行してそこにあるオブジェクトを確認したい場合、呼び出し元はそれら自体を保持する必要があります。

良い解決策は:

-(UIButton*) getTheButton() {
    UIButton* myButton = [[UIButton alloc] init];
    return [myButton autorelease];  // if you don't do autorelease, memory will leak
} 

次に、発信者で:

- (void)caller {
  UIButton *button = [[self getTheButton] retain];
}

これを行うことはできません:

-void operateOnTheButton(UIButton* button) {
    [button release];
    button = [[UIButton alloc] init];
} 

理由:operateOnTheButtonはボタンを所有していないため、ボタンを離してはなりません。ボタンを送って、電話をかけた後、別のボタンがあるとどうなりますか。OperateOnButtonは、パラメーターを割り当て/保持/コピーしません。それを解放する権利はありません。それはあなたにいくつかの問題を引き起こす可能性があります:

1 / EXEC_BAD_ACCESS:オブジェクトを所有していないメソッド内でリリースすると、誰かがそれを使用する可能性があります

2 /メモリがまだリークしています:リリースは、メモリをすぐに削除することを意味するものではありません。保持カウントを1だけデクリメントします。つまり、ボタンオブジェクトが渡されたときにretainCountが2の場合、それを解放すると、retainCount 1のみが作成され、オブジェクトのメモリはまだ削除されません。

3 /ボタンオブジェクトもリークしています:ボタンオブジェクトが解放されていることを誰も確認できません。あなたはそれを所有しているので、あなたはそれを自分で解放しなければなりません、さもなければ、ボタンオブジェクトは漏れます

于 2010-07-23T02:48:40.237 に答える
1
  1. allocこのシナリオは正常ですが、誤ってリリースを忘れないようにするために、同じ行で自動リリースすることを好む人もいます(私自身も含まれます) 。

  2. init通常はを呼び出しませalloc。オブジェクトで作成する場合、allocが最初にinit呼び出され、次に新しく割り当てられたインスタンスで呼び出されます。

  3. このシナリオはかなり正しいです。ただし、保持してもコピーは作成されません。

  4. Objective-Cでは、オブジェクトは常にポインタによって参照されますが、これはC++とは異なります。文字列を返すメソッドを作成している場合は、構造体自体NSString*ではなく、を返します。NSString

次のコードスニペットは、実際にはメモリリークを引き起こします。

-(void) operateOnTheButton:(UIButton*)button {
    [button release];
    button = [[UIButton alloc] init];
} 

buttonはローカル変数であり、スコープ外になると、リリースされていないためにリークします。このoperateOnTheButton:方法で何ができるのかよくわかりません。

于 2010-07-23T02:58:35.017 に答える
0

AutoReleaseを避けたいのはなぜですか?それが行われるべき方法です...

また、いくつかのアドバイス:

多くの人がiPhoneで行うエラーの1つは、UIViewControllerのviewDidLoadメソッドでメモリを割り当ててから、viewDidUnloadメソッドではなくdeallocメソッドでメモリを解放することです。

ビューは複数回ロードできることを常に考慮してください。

于 2010-07-23T02:54:21.413 に答える
0

「クラスの init 関数でオブジェクトを割り当て、クラスの dealloc 関数でオブジェクトを解放する」</p>

まず、クラスの一部である関数はありません。はい、C 関数を記述できます。インスタンスで動作する C 関数を記述できます。しかし、この -(foo)doSomethings (または +(foo)doSomethings) の一部を記述した場合に得られるのは、メッセージ ハンドラーです。そして、メッセージを送信することでそれらを使用します。

これが、-(id)init メッセージ内からインスタンスを割り当てることができない理由です。init は、内部のメモリとスーパークラスのインスタンスと「対話」したいのです。このスペースと機能を割り当てなかったので、メモリの場所がワイルドになるか、(より可能性が高い) ゼロになります。

一方、オブジェクトを解放する方法は、何も解放しません。オブジェクトが破棄されるときにdeallocがオブジェクトに送信されるためです。しかし、(dealloc の中でやりたいので) 解放しないので、オブジェクトが「天国の門」のリストに置かれることはありません: アプリケーションが終了するまで保持カウントを 1 (またはそれ以上) に保ちます。そして、オブジェクトに割り当てられたメモリを OS の空きプールに戻します。dealloc-message はあなたが送信するものではありません。dealloc は、メモリ管理ルーチン専用です。(このメッセージは、インスタンスの親と祖父母のルートである最もスーパーな NSObjectがリリースを受け取り、保持カウントが 1 を下回る必要があることを確認した場合に送信されると思います。)

Objective C でメモリ管理を行いたい場合は独自のフレームワークを作成する必要があります。あなただけの「C++準拠Cocoa」。私見では。

ご挨拶

于 2010-07-24T00:00:28.257 に答える