これまでに見たことのない解決策に出くわしましたが、うまくいくようです...
よくあることですが、いくつかの状態変数が必要なカテゴリがあるので、次のように を使用しますobjc_setAssociatedObject
。
Memento *m = [[[Memento alloc] init] autorelease];
objc_setAssociatedObject(self, kMementoTagKey, m, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
そして、自分のカテゴリが拡張されたインスタンスがいつdealloc
編集されたかを知る必要がありました。私の場合、オブザーバーを on に設定しself
、ある時点でそれらのオブザーバーを削除する必要があるためです。そうしないと、NSKVODeallocateBreak
リークの警告が表示され、悪いことにつながる可能性があります。
retain
関連付けられたオブジェクトが( を使用しているため) edされていたため、それらも dOBJC_ASSOCIATION_RETAIN_NONATOMIC
である必要があり、したがって ed であることに突然気付きました...実際、保存用に作成した単純なストレージ クラスにメソッドを実装していました。私の状態値。そして、私は次のように仮定しました:私の関連オブジェクトは、私のカテゴリーのインスタンスが解放される前に解放されなければなりません! したがって、関連付けられたオブジェクトに、所有者がedであることを認識したときに通知させることができます。関連付けられたオブジェクトを保持していたので、プロパティ ( !として指定されていない) を追加し、所有者を設定してから、関連付けられたオブジェクトのメソッドで所有者のメソッドを呼び出すだけで済みました。release
dealloc
dealloc
dealloc
owner
retain
dealloc
これは、関連するビットを含む、私のカテゴリの .m ファイルの一部を変更したものです。
#import <objc/runtime.h> // So we can use objc_setAssociatedObject, etc.
#import "TargetClass+Category.h"
@interface TargetClass_CategoryMemento : NSObject
{
GLfloat *_coef;
}
@property (nonatomic) GLfloat *coef;
@property (nonatomic, assign) id owner;
@end
@implementation TargetClass_CategoryMemento
-(id)init {
if (self=[super init]) {
_coef = (GLfloat *)malloc(sizeof(GLfloat) * 15);
}
return self;
};
-(void)dealloc {
free(_coef);
if (_owner != nil
&& [_owner respondsToSelector:@selector(associatedObjectReportsDealloc)]) {
[_owner associatedObjectReportsDealloc];
}
[super dealloc];
}
@end
@implementation TargetClass (Category)
static NSString *kMementoTagKey = @"TargetClass+Category_MementoTagKey";
-(TargetClass_CategoryMemento *)TargetClass_CategoryGetMemento
{
TargetClass_CategoryMemento *m = objc_getAssociatedObject(self, kMementoTagKey);
if (m) {
return m;
}
// else
m = [[[TargetClass_CategoryMemento alloc] init] autorelease];
m.owner = self; // so we can let the owner know when we dealloc!
objc_setAssociatedObject(self, kMementoTagKey, m, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return m;
}
-(void) doStuff
{
CCSprite_BlurableMemento *m = [self CCSprite_BlurableGetMemento];
// do stuff you needed a category for, and store state values in m
}
-(void) associatedObjectReportsDealloc
{
NSLog(@"My associated object is being dealloced!");
// do stuff you need to do when your category instances are dealloced!
}
@end
ここで私がどこか (おそらく SO) で学んだパターンは、ファクトリ メソッドを使用して memento オブジェクトを取得または作成します。これで、memento に所有者が設定され、memento のメソッドがコールバックして、編集dealloc
中であることを所有者に知らせます。dealloc
警告:
- 明らかに、関連付けられたオブジェクトを で設定する必要があり
OBJC_ASSOCIATION_RETAIN_NONATOMIC
ます。そうしないと、自動的に保持および解放されません。
- memento/state に関連付けられたオブジェクトが
dealloc
、所有者が編集されている以外の状況で編集される場合、これはより厄介になりますdealloc
...しかし、おそらく、そのイベントを無視するようにいずれかのオブジェクトを訓練することができます。
owner
プロパティを として宣言することはできません。そうしないと、retain
本当に強い参照ループが作成され、どちらのオブジェクトもdealloc
edとして修飾されなくなります。
- 所有者が完全に編集される前に
OBJC_ASSOCIATION_RETAIN_NONATOMIC
関連付けられたオブジェクトが必ず削除されることが文書化されているかどうかはわかりませんが、少なくとも直感的には、そのように発生するようであり、ほとんどそうであるに違いありません。release
dealloc
- の dealloc メソッドの前または後に
associatedObjectReportsDealloc
呼び出されるかどうかはわかりません。これは重要かもしれません! 後で実行した場合、のメンバー オブジェクトにアクセスしようとすると、クラッシュします。そして、私の推測では、それはその後です。TargetClass
TargetClass
オブジェクトを二重リンクしているため、これは少し面倒です。これらの参照をまっすぐに保つには細心の注意が必要です。ただし、スウィズリングやその他のランタイムへの干渉は関係ありません。これは、ランタイムの特定の動作に依存しているだけです。関連付けられたオブジェクトが既にある場合は、便利なソリューションのようです。場合によっては、独自dealloc
の をキャッチするためだけに作成する価値があるかもしれません!