5

コードを書くほど、迷子になります... obj-cの基本を理解するのに時間を無駄にしないように、私(および他の人)のメモリ管理専用のトピックを作成することにしました...次のように更新します新しい質問があります!

以下にいくつかの例を示します。

// myArray is property (retain)
myArray = otherArray;

//myArray isn't a property
myArray = otherArray;

//myArray is a property (retain)
myArray = [[NSArray alloc] init];

//myArray isn't a property
myArray = [[NSArray alloc] init];

---つまり、私が理解している場合... self.myArrayを配置するときは、Xcodeにゲッターまたはセッターを使用するように指示しますが、myArrayを実行するときは、すべての責任がありますよね?

[解決済み]UPDATE1:違いはありますか:

//myArray is a property
myArray = otherArray; // it is only a reference, releasing otherArray will imply releasing myArray
self.myArray = otherArray; // otherArray is sent a retain message so releasing otherArray will still keep myArray in memory

---はい、違いがあります(上記のコメントを参照)

[解決済み]UPDATE2:以下のmyArrayはnilに等しいですか?

NSArray *myArray;

---久美:はい、nilに等しいです。

[解決済み]UPDATE3: 2回の保持にカウントされますか?1つは自己から保持し、もう1つは割り当てから保持しますか?これはメモリリークですか?

self.myArray = [[NSArray alloc] init];

---久美:はい、これはメモリリークです!

[解決済み]UPDATE4:プロパティがすべてを処理しますか?割り当てたり解放したりする必要はありませんか?

self.myArray = [NSArray array];

---ここでは、配列が適切に保持されるようにセッターを使用します

[解決済み]UPDATE5:これら2つのブロックは同じですか?

//myArray is a retained property

self.myArray = [NSArray array]; //retain
self.myArray = nil; //release and set to nil

myArray = [[NSArray alloc] initWithArray]; //retain
self.myArray = nil; //release and set to nil

---久美:はい、同じです

時間をありがとう。

ゴティエ。

4

3 に答える 3

6

まず、あなたがというプロパティと?myArrayというiVarを持っていると仮定します。myArrayその場合、ケース1、2は同一であり、3,4は同一です。現在のクラスのプロパティを設定する必要がある場合は、次のいずれかのメソッドを使用して設定する必要があります。

self.myArray = otherArray;
[self setMyArray:otherArray];

この行myArray = otherArrayはiVarのみを設定し、プロパティは設定しません。

第二に、あなたはメモリ管理について質問しています。ステップ1: Appleのガイドを読んでください。本当に必読です。完全に理解していなくても心配しないでください。月に一度読み続けると、最終的には結晶化します。

ステップ2:この経験則を覚えておいてください:、、、、またはオブジェクトの場合はalloc、そのオブジェクトを解放する責任があります。解放しない場合は、リークされます。copynewretain

他のすべての場合、オブジェクトを解放する責任はありませんが、最終的に解放されます。それを維持する必要がある場合は、それを維持する必要がありますretain(もちろん、後でリリースします)。

例に戻ると、最初の2つのケースでは、保持しないmyArrayと、このコードブロックの後のある時点で解放されます。後でそのオブジェクトにメッセージを送信しようとすると、エラーが発生します。myArray次の2つのケースでは、ある時点でオブジェクトを解放しないと、オブジェクトがリークされます。


アップデート1 非常に大きな違い。2つの線は完全に異なります。ドット構文について理解する重要なことは、これらの2つの線が完全に同等であるということです。

self.myArray = otherArray;
[self setMyArray:otherArray];

2行目がメソッド呼び出しであることに注意してください。理論的には、そのメソッドに必要なものを何でも入れることができます。myArraynilに設定するか、に設定するかsomeOtherArray、Twitterなどを更新することができます。


アップデート2 うん、Obj-Cのポインタはnilに初期化されます。


3を正確に更新します。myArrayプロパティがとして宣言されretainていて、デフォルトのシンセサイザーを使用している場合、メモリリークが発生します。

アップデート5 また正確に。

于 2010-03-22T23:34:12.753 に答える
5

クビの答えは良いです。あなたがそれを理解するまでAppleのガイドを読み直すことは本当に必須です。

それまでの間、偶発的なメモリエラーを回避するために、私が従うこの厳格な一連のプラクティスを採用することでメリットが得られる可能性があります。これらは厳密に必要なものよりも少し多くのタイピングを規定しており、実行時の効率はおそらくわずかに劣りますが、これらのルールに一貫して従うことで、最も一般的なメモリ管理エラーから保護できます。その後、メモリ管理に慣れてきたら、これらのルールから選択的に逸脱することを選択できますが、私はまだめったにそうしません。

  1. 作成するすべてのオブジェクトインスタンス変数のプロパティを宣言します。循環参照を作成するデリゲートのように、クラスが所有していないオブジェクトでない限り、(非アトミック、保持)として宣言します。その場合、そのサイクルですべてのオブジェクトがリークしないように、(非アトミック、割り当て)として宣言します。

    @property (nonatomic, retain) NSString *title;
    @property (nonatomic, assign) id <WidgetDelegate> delegate;
    

  2. オブジェクトインスタンス変数がクラスによる私的使用のみを目的としている場合でも、.mファイルの先頭にあるクラス拡張子でそのプロパティを宣言して、合成されたsetterメソッドがメモリ管理を処理できるようにします。

    // Widget.m
    @interface Widget()
    @property (nonatomic, retain) NSString *privateState;
    @end
    
    @implementation Widget
    @synthesize title, delegate, privateState;
    // ...
    @end
    
  3. インスタンス変数オブジェクトを割り当てるときは常に、selfを使用してプロパティを介して設定してください。

    self.title = @"Title";

  4. Deallocで、すべてのオブジェクトプロパティをnilに設定します。上記の方法に従っている場合、これは同時にインスタンス変数を適切に解放し、EXC_BAD_ACCESSから保護するためにそれらをnilに設定します。プロパティを忘れないように、deallocをクラスの最初のメソッドにします。

    - (void) dealloc {
        self.title = nil;
        self.delegate = nil;
        self.privateState = nil;
        [super dealloc];
    }
    
  5. 作成するすべてのカスタムクラスについて、同じパラメーターを持つinitメソッドに委任し、返されたオブジェクトを自動解放するクラスファクトリメソッドが少なくとも1つあることを確認してください。これにより、コード全体に分散するのではなく、これらのファクトリメソッドへのほとんどすべてのallocおよびinit呼び出しが制限されます。

    - (id)initWithTitle:(NSString *)theTitle delegate:(id )theDelegate {
        if (self = [super init]) {
            self.title = theTitle;
            self.delegate = theDelegate;
            self.privateState = @"start";
        }
        return self;
    }
    + (id)widgetWithTitle:(NSString *)theTitle delegate:(id )theDelegate {
        return [[[self alloc] initWithTitle:theTitle delegate:theDelegate] autorelease];
    }
    
  6. オブジェクトをインスタンス化するときは常に、可能であればファクトリクラスメソッドを使用してインスタンス化してください。これにより、自動解放されたオブジェクトが提供されるため、保持しない限り、解放する必要はありません。

    self.widget = [Widget widgetWithTitle:@"My Widget" delegate:self];
    
  7. 適切なファクトリクラスメソッドを持たないオブジェクトをインスタンス化する必要がある場合は、同じ行で自動リリースするので、後で行うことを忘れないでください。(例外:これをタイトなループで何千回も実行している場合は、手動でリリースしてください。)

    self.containerView = [[[UIView alloc] initWithFrame:self.bounds] autorelease]; 
    
  8. 循環参照を指すデリゲートまたは同様のプロパティを持つオブジェクトをリリースする場合は、最初にそのプロパティをnilに設定します。これにより、オブジェクトがデリゲートよりも長生きし、割り当てが解除された後にデリゲートのメソッドを呼び出そうとした場合に、EXC_BAD_ACCESSが防止されます。

    - (void)dealloc {
        self.widget.delegate = nil;
        self.widget = nil;
        self.containerView = nil;
        [super dealloc];
    }
    

多くの経験豊富な開発者は、これらのすべての慣行に従わなくても、メモリを正常に管理します。メモリ管理を理解していて、メモリ関連のバグが発生する傾向がない場合は、自分に合ったものを使用することをお勧めします。ただし、iPhoneのメモリ管理に慣れていない場合、またはコードが偶発的なメモリ関連のバグに悩まされている場合は、これらの方法が私と同じように役立つことを願っています。

于 2010-03-23T11:28:07.080 に答える
0

これに対する答えを見つけるのに最適な場所は、メモリ管理についてすべて説明している関連するAppleのドキュメントにあります。そうは言っても、ここではivarのみを使用しており、ObjCで生成されたセッターを使用してivarを設定しているわけではありません。クビが言うように、あなたは言わなければならないでしょう

self.myArray = otherArray;

myArrayの「プロパティ」を使用するため。

于 2010-03-22T23:38:43.333 に答える