在某些情况下,您可以推断对象是否被放置在自动释放池中。这个想法是声明一个指向对象的指针,在 @autoreleasepool 块中实例化它,然后验证它是否在块结束后调用了 dealloc。
通过您选择的混合或覆盖dealloc 的任何组合,您必须首先提供一种方法来验证dealloc 是否已被调用。我编写了一个NSObject 类别,它具有以下接口和实现,它提供了一个deallocationDelegate 属性,当对象被释放时,该属性将收到handleDeallocation: 的消息。
@interface NSObject (FunTimes)
@property (nonatomic, assign) id deallocationDelegate;
@end
@implementation NSObject (FunTimes)
+ (void)load
{
Class klass = [NSObject class];
SEL originalSelector = @selector(dealloc);
Method originalMethod = class_getInstanceMethod(klass, originalSelector);
SEL replacementSelector = @selector(funDealloc);
Method replacementMethod = class_getInstanceMethod(klass, replacementSelector);
if(class_addMethod(klass, originalSelector, method_getImplementation(replacementMethod), method_getTypeEncoding(replacementMethod)))
{
class_replaceMethod(klass, replacementSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else
{
method_exchangeImplementations(originalMethod, replacementMethod);
}
}
- (void)funDealloc
{
if (self.deallocationDelegate)
[self.deallocationDelegate performSelector:@selector(handleDeallocation:) withObject:self];
[self funDealloc];
}
static char myKey;
- (void)setDeallocationDelegate:(id)deallocationDelegate
{
objc_setAssociatedObject(self, &myKey, deallocationDelegate, OBJC_ASSOCIATION_ASSIGN);
}
- (id)deallocationDelegate
{
return objc_getAssociatedObject(self, &myKey);
}
@end
我在我的应用程序委托中运行了一些测试代码,只是为了看看它是否有效。我声明了一个NSMutableArray 实例,该实例旨在保存从调用-handleDeallocation 的对象的指针派生的NSValue 实例,我实现如下所示:
- (void)handleDeallocation:(id)toDie
{
NSValue *pointerValue = [NSValue valueWithPointer:toDie];
[self.deallocatedPointerValues addObject:pointerValue];
}
现在,这是我运行的一个 sn-p。 SomeClass 是一个 NSObject 子类,没有其他属性或方法。
self.deallocatedPointerValues = [NSMutableArray 数组];
SomeClass *arsc = nil;
@autoreleasepool {
arsc = [[[SomeClass alloc] init] autorelease];
arsc.deallocationDelegate = self;
NSValue *prePointerValue = [NSValue valueWithPointer:arsc];
BOOL preDeallocated = [self.deallocatedPointerValues containsObject:prePointerValue];
NSLog(@"PreDeallocated should be no is %d",preDeallocated);
}
NSValue *postPointerValue = [NSValue valueWithPointer:arsc];
BOOL postDeallocated = [self.deallocatedPointerValues containsObject:postPointerValue];
NSLog(@"Post deallocated should be yes is %d",postDeallocated);
在这种情况下,可以验证arsc(代表自动释放的SomeClass)指向的对象由于结束了@autoreleasepool块而被释放。
这种方法有几个重大限制。一,当retain 的其他消息可能被发送到从您的工厂方法返回的对象时,这不起作用。此外,这应该不言而喻,swizzling dealloc 应该只在实验环境中进行,我认为有些人会争辩说它不应该在测试中进行 swizzled(显然它不应该在生产中进行 swizzled!)。最后,更重要的是,这不适用于诸如 NSString 之类的 Foundation 对象,这些对象的优化方式并不总是清楚您是否正在创建新实例。因此,这对于您自己的自定义对象来说是最合适的(如果有的话)。
最后,我认为这样做并不实际。我觉得这比它值得做的工作更多,而且适用范围如此之小,因为在内存管理方面,花时间学习工具更好,成为更好的投资。而且,当然,由于 ARC 的优势,这种方法从一开始就是过时的。无论如何,如果您确实需要编写此类测试,并且可以解决此处的限制,请随时调整此代码。我很想知道它在实际测试环境中的表现如何。