How to access dealloc method in a category?

I need to perform an action in the dealloc method of a category. I tried swizzling, but this does not work (and this is not a great idea).

In case someone asks for an answer, no, I can not use a subclass, this is specifically for the category.

I want to perform a delayed action with [NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:]or [self performSelector:withObject:afterDelay:]and cancel it on dealloc.

The first problem is that it NSTimerkeeps the goal, which I don't want. [self performSelector:withObject:afterDelay:]not saved, but I need to call [NSObject cancelPreviousPerformRequestsWithTarget:selector:object:]in the method deallocor we will get a failure.

Any suggestions on how to do this in a category?

+5
source share
3 answers

, , , , ...

, , , , objc_setAssociatedObject, :

Memento *m = [[[Memento alloc] init] autorelease];
objc_setAssociatedObject(self, kMementoTagKey, m, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

, dealloc ed. , self - , NSKVODeallocateBreak, .

, retain ed (- OBJC_ASSOCIATION_RETAIN_NONATOMIC), release d , dealloc ed... dealloc , . : ! , , , , dealloc ed! , 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

, - (, S.O.), factory . , memento dealloc , , dealloc ed

:

  • , OBJC_ASSOCIATION_RETAIN_NONATOMIC, .
  • , memento/state dealloc ed , dealloc ed... , , .
  • owner retain, , dealloc ed!
  • , , OBJC_ASSOCIATION_RETAIN_NONATOMIC release d , dealloc ed, , , , , ,.
  • , associatedObjectReportsDealloc dealloc TargetClass - ! , - TargetClass, ! , .

, , , . swizzling - . , . , , , dealloc s!

+4

, , , , - , . , - , , swizzling.

, , DeallocHook, NSObject , NSObject . - :

// Instead of directly messing with your class -dealloc method, attach
// the hook to your instance and do the cleanup in the callback 
[DeallocHook attachTo: yourObject 
             callback: ^{ [NSObject cancelPrevious... /* your code here */ ]; }];

DeallocHook objc_setAssociatedObject:

@interface DeallocHook : NSObject
@property (copy, nonatomic) dispatch_block_t callback;

+ (id) attachTo: (id) target callback: (dispatch_block_t) block;

@end

:

#import "DeallocHook.h"
#import <objc/runtime.h>

// Address of a static global var can be used as a key
static void *kDeallocHookAssociation = &kDeallocHookAssociation;

@implementation DeallocHook

+ (id) attachTo: (id) target callback: (dispatch_block_t) block
{
    DeallocHook *hook = [[DeallocHook alloc] initWithCallback: block];

    // The trick is that associations are released when your target
    // object gets deallocated, so our DeallocHook object will get
    // deallocated right after your object
    objc_setAssociatedObject(target, kDeallocHookAssociation, hook, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    return hook;
}


- (id) initWithCallback: (dispatch_block_t) block
{
    self = [super init];

    if (self != nil)
    {
        // Here we just copy the callback for later
        self.callback = block;
    }
    return self;
}


- (void) dealloc
{
    // And we place our callback within the -dealloc method
    // of your helper class.
    if (self.callback != nil)
        dispatch_async(dispatch_get_main_queue(), self.callback);
}

@end

. Apple Objective-C ( , ).

, , , . , , .

+8

, , : NSTimer , dealloc, . 1 , , . dealloc. (Pre-ARC, retain release , .)

NSThread , : "". , , , . , ( , ), : , . : dealloc .

. , - - , , , , ( ) - . , , NSTimer , GCD dispatch_after(). , . ( NSTimer ), , , nil, , .

+2

All Articles