我试图编写一些代码,当通过调用-[NSObject dealloc]
方法释放任何对象时将调用这些代码。我理解这是一个坏主意,不会追求它(所以请不要指出这一点),但是在此过程中我发现像NSDictionary和NSString这样的类是免费的,与CFDictionary等核心基础对应物桥接。和CFString在最终版本发布时不会调用-dealloc
。
此代码演示了这种现象:
- (void)loggedDealloc {
NSLog(@"Deallocation of %@", self.class);
[self loggedDealloc];
}
- (void)testDeallocSwizzleOnTestObject {
Method deallocMethod = class_getInstanceMethod([TestObject class], NSSelectorFromString(@"dealloc"));
Method loggedDeallocMethod = class_getInstanceMethod([self class], @selector(loggedDealloc));
method_exchangeImplementations(deallocMethod, loggedDeallocMethod);
TestObject * testObject = [[TestObject alloc] init];
testObject = nil; // calls release under ARC
method_exchangeImplementations(deallocMethod, loggedDeallocMethod);
}
- (void)testDeallocSwizzleOnNSDictionary {
Method deallocMethod = class_getInstanceMethod([NSDictionary class], NSSelectorFromString(@"dealloc"));
Method loggedDeallocMethod = class_getInstanceMethod([self class], @selector(loggedDealloc));
method_exchangeImplementations(deallocMethod, loggedDeallocMethod);
NSDictionary * dictionary = [[NSDictionary alloc] init];
dictionary = nil; // calls release under ARC
method_exchangeImplementations(deallocMethod, loggedDeallocMethod);
}
- (void)testDeallocSwizzleOnNSString {
Method deallocMethod = class_getInstanceMethod([NSString class], NSSelectorFromString(@"dealloc"));
Method loggedDeallocMethod = class_getInstanceMethod([self class], @selector(loggedDealloc));
method_exchangeImplementations(deallocMethod, loggedDeallocMethod);
NSDictionary * dictionary = [[NSDictionary alloc] init];
dictionary = nil; // calls release under ARC
method_exchangeImplementations(deallocMethod, loggedDeallocMethod);
}
在上面的测试中,只有Swizzling的测试对象才会导致重新分配的记录。 NSDictionary和NSString的混合没有效果。
我怀疑这是因为免费桥接类实现-release
来执行CFRelease而不是调用[super release]
,因此内核被Core Foundation解除分配而没有调用-dealloc
发生了。
任何人都可以确认是这种情况,是否记录在任何地方?如果是这样,有没有办法将自定义代码注入这些免费桥接类的解除分配?
答案 0 :(得分:3)
(嘿。去过那里。做完了。:)
仅对各种类的子类保证对dealloc
的调用。有许多类 - 主要是各种CF / NS桥接类 - 从未调用dealloc
,因为从来没有必要这样做[内部实现细节]。
要做你想做的事情,将子类化为所需的类,将原始类的实例封装为后备存储,然后覆盖原始方法(每个类集群类都有一个非常小的集合)原始方法 - 我认为NSString
具有所有2种方法)然后覆盖该新类的内存管理方法。因为它是一个子类,你在现有类中看到的“短路”将不再发挥作用。