Run Code at Deallocation of Any Object

I was reading this article by Jeff Kelley and trying to do the same. However the code was written before ARC was adopted and now fails to compile.

http://blog.slaunchaman.com/2011/04/11/fun-with-the-objective-c-runtime-run-code-at-deallocation-of-any-object/

The main problem is in this part of the printout, some casting errors and then blocked release messages. I found it to be a very interesting example but I can't seem to get it to work.

The problems are:

0. Autosynthesized property 'block' will use synthesized instance variable '_block', not existing instance variable 'block' on the @implementation JKBlockExecutor

1. Cast of block pointer type 'voidBlock' (aka 'void (^)(void)') to C pointer type 'const void *' requires a bridged cast and Cast of C pointer type 'void *' to block pointer type 'typeof (aBlock)' (aka 'void (^__strong)(void)') requires a bridged cast" on the block = Block_copy(aBlock); line

2. Cast of block pointer type 'voidBlock' (aka 'void (^)(void)') to C pointer type 'const void *' requires a bridged cast on Block_release(block);

typedef void (^voidBlock)(void);

@interface JKBlockExecutor : NSObject {
    voidBlock   block;
}

@property (nonatomic, readwrite, copy) voidBlock    block;

- (id)initWithBlock:(voidBlock)block;

@end

@implementation JKBlockExecutor

@synthesize block;

- (id)initWithBlock:(voidBlock)aBlock
{
    self = [super init];

    if (self) {
        block = Block_copy(aBlock);
    }

    return self;
}

- (void)dealloc
{
    if (block != nil) {
        block();
        Block_release(block);
    }

    [super dealloc];
}

@end

This is where he creates a category on NSObject.

const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;

@interface NSObject (JK_RunAtDealloc)

- (void)runAtDealloc:(voidBlock)block;

@end

@implementation NSObject (JK_RunAtDealloc)

- (void)runAtDealloc:(voidBlock)block
{
    if (block) {
        JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];

        objc_setAssociatedObject(self,
                                 runAtDeallocBlockKey,
                                 executor,
                                 OBJC_ASSOCIATION_RETAIN);

        [executor release];
    }
}

@end

This is how you execute the example.

NSObject *foo = [[NSObject alloc] init];

[foo runAtDealloc:^{
    NSLog(@"Deallocating foo!");
}];

[foo release];

Or another way to get other information.

NSObject *foo = [[NSObject alloc] init];

__block id objectRef = foo;

[foo runAtDealloc:^{
    NSLog(@"Deallocating foo at address %p!", objectRef);
}];

[foo release];

Can this code be fixed somehow? I took out all the release messages to no avail.


Code below builds and works (or at least seems so), and prints "Deallocating foo!" when I expect it to print it. Part 1:

typedef void (^voidBlock)(void);

@interface JKBlockExecutor : NSObject {
    voidBlock   block;
}

@property (nonatomic, readwrite, copy) voidBlock    block;

- (id)initWithBlock:(voidBlock)block;

@end

@implementation JKBlockExecutor

@synthesize block = block;

- (id)initWithBlock:(voidBlock)aBlock
{
    self = [super init];

    if (self) {
        block = [aBlock copy];
    }

    return self;
}

- (void)dealloc
{
    if (block != nil) {
        block();
        block = nil;
    }
}

@end

Part 2:

const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;

@interface NSObject (JK_RunAtDealloc)

- (void)runAtDealloc:(voidBlock)block;

@end

@implementation NSObject (JK_RunAtDealloc)

- (void)runAtDealloc:(voidBlock)block
{
    if (block) {
        JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];

        objc_setAssociatedObject(self,
                                 runAtDeallocBlockKey,
                                 executor,
                                 OBJC_ASSOCIATION_RETAIN);
    }
}

@end

Testing if it works:

@autoreleasepool {
        NSObject *foo = [[NSObject alloc] init];

        [foo runAtDealloc:^{
            NSLog(@"Deallocating foo!");
        }];
    }

EDIT

Changed Block_release(block); to block = nil;


If you want to know more about the code below ,please go to Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object

Part 1:create one class: the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。

// .m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。


typedef void (^voidBlock)(void);

@interface CYLBlockExecutor : NSObject 

- (id)initWithBlock:(voidBlock)block;

@end


// .m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。

#import "CYLBlockExecutor.h"

@interface CYLBlockExecutor() {
    voidBlock _block;
}
@implementation CYLBlockExecutor

- (id)initWithBlock:(voidBlock)aBlock
{
    self = [super init];

    if (self) {
        _block = [aBlock copy];
    }

    return self;
}

- (void)dealloc
{
    _block ? _block() : nil;
}

@end

Part 2:core code:use runtime to realize cyl_runAtDealloc method

// CYLNSObject+RunAtDealloc.h file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// use runtime to realize cyl_runAtDealloc method

#import "CYLBlockExecutor.h"

const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;

@interface NSObject (CYLRunAtDealloc)

- (void)cyl_runAtDealloc:(voidBlock)block;

@end


// CYLNSObject+RunAtDealloc.m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// use runtime to realize cyl_runAtDealloc method

#import "CYLNSObject+RunAtDealloc.h"
#import "CYLBlockExecutor.h"

@implementation NSObject (CYLRunAtDealloc)

- (void)cyl_runAtDealloc:(voidBlock)block
{
    if (block) {
        CYLBlockExecutor *executor = [[CYLBlockExecutor alloc] initWithBlock:block];

        objc_setAssociatedObject(self,
                                 runAtDeallocBlockKey,
                                 executor,
                                 OBJC_ASSOCIATION_RETAIN);
    }
}

@end

How to use :

#import "CYLNSObject+RunAtDealloc.h"

then

    NSObject *foo = [[NSObject alloc] init];

    [foo cyl_runAtDealloc:^{
        NSLog(@"Deallocating foo!");
    }];
链接地址: http://www.djcxy.com/p/44916.html

上一篇: 似乎无法使用ARC从NSString *转换为CFString *

下一篇: 在取消分配任何对象时运行代码