NSKVODeallocateBreak
, which allows you to interrupt the execution of the application at the moment when the object subscribed to the events is destroyed in order to track its lifetime and remove the problem.@synthesize
unfolds), then you can read my old article on this issue. . The rest I ask to the table.dealloc
call of the signatory object when subscribing to an event and report it to the developer. However, here's a bad luck - it is impossible to intercept dealloc
standard means (or, at least, I have not found such a method). @interface NSObject (NSObjectDeallocInfo) -(void)dealloc_override; @end @implementation NSObject (NSObjectDeallocInfo) +(void)load { method_exchangeImplementations(class_getInstanceMethod(self, @selector(dealloc)), class_getInstanceMethod(self, @selector(dealloc_override))); } -(void)dealloc_override { [self dealloc_override]; } @end
[self dealloc_override]
actually now leads to the standard method. static void* AW_EVENTHANDLER_KEY = (void *)0x2781;
NSObject
class, using the same category that we used to override the method. @interface NSObject (NSObjectDeallocInfo) @property (nonatomic, assign) AWEventHandlersList *attachedEventHandler; -(void)dealloc_override; @end @implementation NSObject (NSObjectDeallocInfo) +(void)load { method_exchangeImplementations(class_getInstanceMethod(self, @selector(dealloc)), class_getInstanceMethod(self, @selector(dealloc_override))); } -(void)dealloc_override { [self dealloc_override]; } -(AWEventHandlersList *)attachedEventHandler { return (AWEventHandlersList *)objc_getAssociatedObject(self, AW_EVENTHANDLER_KEY); } -(void)setAttachedEventHandler:(AWEventHandlersList *)attachedEventHandler { objc_setAssociatedObject(self, AW_EVENTHANDLER_KEY, attachedEventHandler, OBJC_ASSOCIATION_ASSIGN); } @end
NSObject
has a virtual property attachedEventHandler
, which we will use to store the information we need.AWEventHandlersList
class AWEventHandlersList
that it writes the object of the AWEventHandlersList
in this field and add a method that returns YES
if the object is subscribed to the event. -(void)addReceiver:(id)receiver delegate:(SEL)delegate { [self removeReceiver:receiver delegate:delegate]; [receiver setAttachedEventHandler:self]; [_handlers addObject:[AWEventHandler handlerWithTarget:receiver method:delegate]]; } -(void)removeReceiver:(id)receiver delegate:(SEL)delegate { [receiver setAttachedEventHandler:nil]; for(AWEventHandler *handler in [[_handlers copy] autorelease]) if(handler.method == delegate && handler.target == receiver) [_handlers removeObject:handler]; } -(BOOL)isReceiverInList:(id)receiver { for(AWEventHandler *handler in _handlers) if(handler.target == receiver) return YES; return NO; } -(void)clearReceivers { for(AWEventHandler *handler in _handlers) [handler.target setAttachedEventHandler:nil]; [_handlers removeAllObjects]; }
-(void)dealloc_override { AWEventHandlersList *handler = self.attachedEventHandler; if(handler) if([handler isReceiverInList:self]) { NSLog(@"Event handler (%@) target is released while subscribed", handler.name); [NSException raise:@"E_HANDLERRELEASED" format:@"Event handler (%@) target is released while subscribed", handler.name]; } [self dealloc_override]; }
Source: https://habr.com/ru/post/168201/
All Articles