我只是偶然发现了一个我以前从未见过的解决方案,而且似乎有效......
我有一个类别——就像一个经常做的那样——需要一些状态变量,所以我使用objc_setAssociatedObject
,像这样:
Memento *m = [[[Memento alloc] init] autorelease];
objc_setAssociatedObject(self, kMementoTagKey, m, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
而且,我需要知道我的类别扩展的实例何时被dealloc
编辑。就我而言,这是因为我设置了观察者self
,并且必须在某个时候移除这些观察者,否则我会收到NSKVODeallocateBreak
泄漏警告,这可能会导致坏事。
突然间我恍然大悟,因为我的关联对象正在被retain
编辑(因为使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
),它们也必须被编辑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 上)使用工厂方法来获取或创建纪念品对象。现在它将所有者设置在备忘录上,并且备忘录的dealloc
方法回调以让所有者知道它正在被dealloc
编辑
注意事项:
- 显然,您必须将关联对象设置为
OBJC_ASSOCIATION_RETAIN_NONATOMIC
,否则它不会自动为您保留和释放。
- 如果您的纪念品/状态相关对象
dealloc
在其他情况下被编辑而不是被编辑的所有者,这将变得更加棘手dealloc
......但您可能会训练一个对象或另一个对象以忽略该事件。
- 该
owner
属性不能声明为retain
,否则您将真正创建一个强引用循环,并且这两个对象都没有资格被dealloc
编辑!
- 我不知道在所有者被完全编辑之前
OBJC_ASSOCIATION_RETAIN_NONATOMIC
关联对象必须是d 的记录,但它似乎是这样发生的,并且几乎必须是这种情况,至少直观地说。release
dealloc
- 我不知道是否
associatedObjectReportsDealloc
会在's dealloc方法之前或之后被调用——这可能很重要!如果它之后运行,如果您尝试访问成员对象,您将崩溃!我的猜测是之后。TargetClass
TargetClass
这有点混乱,因为您正在双重链接您的对象,这需要您非常小心地保持这些引用的正确性。但是,它不涉及 swizzling 或对运行时的其他干扰——这仅依赖于运行时的某种行为。如果您已经有关联的对象,这似乎是一个方便的解决方案。在某些情况下,创建一个只是为了抓住你自己的 s 可能是值得dealloc
的!