まず第一に:retainCount
役に立たない。
これは、MyLayer の自動解放されたインスタンスを返します。
_myLayer = [MyLayer node];
これは次と同等です。
_myLayer = [[[MyLayer alloc] init] autorelease];
他のコードなしでそのままにしておくと_myLayer
、 init メソッドが戻った後しばらくして、 がダングリング ポインターになります。次回自動解放プールがパージされるのは間違いなく、私の記憶が正しければ、cocos2d のすべてのフレームで発生します。ARC では、ivar 自体がデフォルトで強い参照になるため、レイヤーは保持され、期待どおりに割り当て解除されません。したがって、autorelease とその動作が気に入らない場合は、ARC を使用してください。;)
次に、レイヤーを子として追加します。これにより、レイヤーが配列に配置されます。つまり、レイヤーが保持されます。
[self addChild:_myLayer];
そのため、レイヤーがシーンの子である限り、割り当ては解除されません。
そして今、あなたの前の多くの人と同じように、レイヤーが解放されないという問題を修正するために間違った場所を見ていました. これを dealloc で行うと、余分なリリースが追加されます。
[_myLayer release];
実際の問題はレイヤーが解放されないことであり、ここで強制的に解放されるため、これは今のところ問題なく機能します。ただし、しばらくすると、シーンの子配列が解放され、各オブジェクトに解放が送信され、レイヤーの過剰解放によるクラッシュが発生します。
したがって、追跡する必要がある実際の問題は、レイヤーが割り当て解除されない理由です。そして、ここで私はより多くの問題を感じます:
シーン全体を解放できます
それが現場にメッセージを送っていたという意味ならrelease
、それは間違っています。そしてまた、これはシーンを過剰に解放します。replaceScene または同様のメソッドを呼び出すと、Cocos2d はシーンを消去します。シーン自体も通常は自動解放されます。これは、node
またはscene
クラス メソッドを介して作成された場合に確実です。
それがあなたがしていることではなく、レイヤーが解放されない場合は、保持サイクルがあるかどうかを確認してください。それとも、レイヤーがシーンの前に割り当て解除されることを期待しているだけですか? それは必ずしもこの順序である必要はありません。
2 つ (またはそれ以上) の兄弟ノードを互いに保持する (つまり、レイヤー A がレイヤー B を保持し、レイヤー B がレイヤー A を保持する) ことによって、または保持された参照を保持する _myLayer などの親を保持する兄弟によって保持サイクルを簡単に作成できます。シーンに(ところで、self.parentを介してアクセスするのと同じです)。
保持サイクルを除いて、これらすべての問題がほぼ瞬時に解消されるため、ARCを使用するように言っています。しかし、リテイン サイクルの場合は、弱い参照をゼロにするという非常に単純で効果的な解決策を提供します。
たとえば、レイヤー参照をインターフェイスで弱いとして宣言すると、レイヤーが保持されることを心配する必要がなくなります。
__weak MyLayer *_myLayer;
さらに、レイヤーが解放されると、_myLayer は自動的に nil に設定されます。そしてこれは、 の場合のように後で発生するのではなく、レイヤーに強い参照がなくなった場合に発生しautorelease
ます。
肯定的な副作用は、次のことを安全に実行できるようになったことです。
@interface LayerA : CCLayer
@property (weak) LayerB* layerB;
@end
@interface LayerB : CCLayer
@property (weak) LayerA* layerA;
@end
MRC では、適切にレイヤーを割り当て、dealloc メソッドの前にレイヤーを nil に設定しないと、保持サイクルが作成されます。リテイン サイクルの厄介な点は、dealloc メソッド内で解決できないことです。これは、定義上、リテイン サイクルに参加しているすべてのオブジェクトが割り当て解除されないためです。cocos2d でこれを行う典型的な場所はクリーンアップ メソッドです。
しかし、ARC ではまったく問題ありません。他のレイヤーの参照が保持されていない (弱い) ため、いずれかまたは両方のレイヤーの割り当てが解除されます。いずれかのレイヤーの割り当てが解除されると、参照は nil に設定されるため、クラッシュは発生しません。
私は 2 年間、ARC のみで開発を行ってきました。振り返ることはありませんでした。メモリ管理に関連するエラーの割り当てがほぼゼロになりました。ばかげています。私がときどき調べなければならない唯一のことは、弱参照が nil になるとは思わないときに nil になることです。通常、それは、オブジェクトがどこかに強い参照を持っていると誤って想定しているときに、そうではありません。
ARC を使用すると非常に時間の節約になるので、これを学びたいと思っているとしても、Objective-C 開発の昔のメモリ管理がどのように機能していたかに完全に興味を持ったほうがよいでしょう。おばあちゃんがまだ最初の iPhone のコードを書いていたときのようにね! :)
PS: ARC を使用するときにメモリ管理の制御を放棄するというのは神話です。たとえ短時間であっても、コントロールを取り戻すためにできる巧妙なトリックがたくさんあります。主にブリッジキャスティングを使用。したがって、ARC がさらに数サイクルかかり、それがタイトなループになる可能性がある場合でも、MRC を使用してコードを手動で最適化できます (必要な場合は、おそらく必要ないでしょう)。これはこの回答の範囲を超えています(私はすでに行き過ぎました)が、これらのオプションは存在しますが、それらを実行する必要はほとんどありません。
これが、私が ARC を使用することに強引である理由です。IMO。