Why don't classes that seamlessly connect with Core Foundation peers fail to call -dealloc after the final release?

I tried to write code that would be called when an object was freed by the swizzling method -[NSObject dealloc] . I understand that this is a bad idea and will not pursue it (therefore, please refrain from specifying this), but along the way I found that classes such as NSDictionary and NSString that duty-free connect with Core Foundation analogies such as CFDictionary and CFString do not call -dealloc after the final version.

This code demonstrates this phenomenon:

 - (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); } 

In the above tests, only a TestObject check will result in the release log being logged. Rewinding NSDictionary and NSString is not affected.

I suspect this is because the free bridge classes implement -release to execute CFRelease and not to call [super release] , so the memory is freed from Core Foundation and the -dealloc call is not made at all.

Can anyone confirm that this is documented? If so, is there a way to inject custom code into the release of these countless bridge classes?

+4
source share
1 answer

(Hehe was there. Did it. :)

Dealloc calls are guaranteed only for subclasses of different classes. There are several classes - basically different CF / NS bridge classes for which dealloc never called because you never need to do this [internal implementation detail].

To do what you want to do, it is much easier to subclass the required class, encapsulate an instance of the source class as a backup storage and then override the primitive methods (each class of the cluster class has a very minimal set of primitive methods - I think that NSString has all 2 methods ), and then overrides the memory management methods in this new class. Since this is a subclass, the โ€œshort circuitโ€ that you see with existing classes will no longer enter the game.

+3
source

Source: https://habr.com/ru/post/1390538/


All Articles