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.
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;