Objective-C运行时 - 在任何对象的释放时运行代码

时间:2014-04-02 11:23:18

标签: objective-c objective-c-blocks objective-c-runtime objective-c-category

我正在阅读杰夫凯利的这篇文章并试图做同样的事情。但是代码是在ARC被采用之前编写的,现在无法编译。

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

主要问题是打印输出的这一部分,一些播放错误,然后阻止发布消息。我发现这是一个非常有趣的例子,但我似乎无法让它发挥作用。

问题是:

0。自动合成属性'阻止'将使用合成的实例变量' _block',而不是现有的实例变量' block' on @implementation JKBlockExecutor

1。块指针类型的转换' voidBlock' (又名' void(^)(void)')到C指针类型' const void *'需要桥接演员 C指针类型的演员' void *'阻止指针类型' typeof(aBlock)' (aka' void(^ __ strong)(void)')需要一个桥接演员" 块= Block_copy(aBlock);的

2。块指针类型的转换' voidBlock' (又名' void(^)(void)')到C指针类型' const void *'需要一个桥接演员 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

这是他在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

这就是你执行这个例子的方式。

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

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

[foo release];

或获取其他信息的其他方式。

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

__block id objectRef = foo;

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

[foo release];

这段代码能以某种方式修复吗?我拿出所有的发布消息都无济于事。

2 个答案:

答案 0 :(得分:1)

下面的代码构建和工作(或至少看起来如此),并打印“Deallocating foo!”当我希望它打印出来的时候。第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

第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

测试是否有效:

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

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

修改

Block_release(block);更改为block = nil;

答案 1 :(得分:0)

如果您想了解有关以下代码的更多信息,请转到Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object

第1部分:创建一个类:当发生这种情况时我们想要发布的对象---这个类就像一个事件:当目标obj dealloc时,它就会发生。使用块来执行事件。

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

第2部分:核心代码:使用runtime来实现cyl_runAtDealloc方法

// 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

使用方法:

#import "CYLNSObject+RunAtDealloc.h"

然后

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

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