【问题标题】:Callback method before deallocating any Object释放任何对象之前的回调方法
【发布时间】:2011-05-11 06:19:01
【问题描述】:

有没有办法在释放任何 NSObject 类对象之前调用方法。

是否可以为 NSObject 类编写自定义 dealloc 方法,以便
我们可以在释放该对象之前调用任何方法吗?

由于垃圾收集器不适用于 iPhone,我想创建一个小型框架,在运行时处理内存泄漏并为泄漏创建日志文件(我知道有工具可以识别泄漏,但仍然用于研发,但不想要实现垃圾收集器算法)。

我们正在尝试维护已分配对象的列表。

例如:

A *a=[[A alloc]init];

NSString * veribaleAddress=[NSString stringWithFormat:@"%p",&a];

NSString *allocatedMemoryAddress=[NSString stringWithFormat:@"%p",a];

// Global dictionary for maintaining a list of object  NSMutableDictionary *objects;


[objects setValue: allocatedMemoryAddress forKey: veribaleAddress];

但是当任何对象被解除分配时,我想第一次查看该对象的地址是否存在于字典中。如果地址存在,则将其从字典中删除。

请指导我,是否可能。

谢谢

【问题讨论】:

  • 如果你告诉我们你想要完成什么,你会得到更好的答案。
  • 您可能可以调配-[NSObject dealloc],但这通常是一个坏主意™。你到底想完成什么?
  • 我不确定我是否理解正确。你想在dealloc中还是在dealloc之前调用一个方法。我想您知道您从不直接发送 dealloc 消息。而是通过释放 NSObject 协议方法间接调用对象的 dealloc 方法(如果释放消息导致接收者的保留计数变为 0)
  • 大家好,我再次编辑我的问题。请检查一下。
  • a) 你不应该这样做 b) 如果你仍然相信这是值得的,你的实现将需要重新设计 c) 你不应该这样做

标签: iphone objective-c cocoa-touch cocoa


【解决方案1】:

这里有一个 example gist 展示如何使用 swizzledealloc 方法,如果这就是你所追求的。主要部分代码:

void swizzle(Class c, SEL orig, SEL patch)
{
    Method origMethod = class_getInstanceMethod(c, orig);
    Method patchMethod = class_getInstanceMethod(c, patch);

    BOOL added = class_addMethod(c, orig,
        method_getImplementation(patchMethod),
        method_getTypeEncoding(patchMethod));

    if (added) {
        class_replaceMethod(c, patch,
            method_getImplementation(origMethod),
            method_getTypeEncoding(origMethod));
        return;
    }

    method_exchangeImplementations(origMethod, patchMethod);
}

id swizzledDealloc(id self, SEL _cmd)
{
    // …whatever…
    return self;
}

const SEL deallocSel  = @selector(dealloc);
// If using ARC, try:
//  const SEL deallocSel  = NSSelectorFromString(@"dealloc");

const SEL swizzledSel = @selector(swizzledDealloc);
class_addMethod(c, swizzledSel, (IMP) swizzledDealloc, "@@:");
swizzle(c, deallocSel, swizzledSel);

正如 Bavarious 所说,这是黑魔法,我永远不会在生产中使用它。

【讨论】:

  • +1 是第一个详细说明正确方法的人(“正确”是指一个 方法实现 的方法永远不应该存在)
  • +1 回应了你和 Justin 的保留意见,但在极少数情况下,swizzling 是一种合法的工具——我认为这就是 KVO 的实施方式。
  • BTW swizzledDealloc 需要调用原始的 dealloc 否则对象实际上不会被释放。
  • 我已经自定义了 swizzelDealloc 代码,如下所示,因为我需要为每个获取 dealloc 的对象回调方法,所以我为创建 NSObject 类别并添加 swizzelDealloc 方法的 NSObject 类的 dealloc 方法进行了 swizzle如下.. '-(void)swizzledDealloc' { //调用处理程序方法... classplaceDeallocated([self class]); [self dealloc];//调用dealloc方法的默认实现.. classReplaceDeallocated([self class]); }'
  • 我很f... 一个月前我确实为UIVIew 调整了dealloc,现在我意识到UIViews 在调用dealloc 时会随机释放。我必须告诉我的老板我的魔法不再起作用了……我证明了调配 dealloc 是……失败了
【解决方案2】:

您也许可以使用objc_setAssociatedObject 来跟踪对象的生命周期。像这样的:

标题:

// SGBObjectTracker.h

typedef void (^SGBObjectTrackerCallback)(id trackedObject); 

@interface SGBObjectTracker : NSObject

@property (nonatomic, assign) id trackedObject;
@property (nonatomic, copy) SGBObjectTrackerCallback callback;

+(void) trackObject:(id)object withCallback:(SGBObjectTrackerCallback)callback;

@end

实施:

// SGBObjectTracker.m

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

@implementation 

@synthesize trackedObject, callback;

-(void) dealloc
{
    callback(trackedObject);
    [super dealloc];
}

+(void) trackObject:(id)object withCallback:(SGBObjectTrackerCallback)callback
{
    SGBObjectTracker *tracker = [[self alloc] init];
    tracker.callback = callback;
    tracker.trackedObject = object;
    objc_setAssociatedObject(object, _cmd, tracker, OBJC_ASSOCIATION_RETAIN);
    [tracker release];
}

@end

这利用了关联对象在与其关联的对象被释放时被释放的事实。它不适用于启用 NSZombies,如果您使用 ARC 或其他与保留计数混淆的东西,它可能会中断。我不会指望能够在回调期间使用有问题的对象,但它的地址应该仍然可以,这就是您似乎需要的。

【讨论】:

  • 关联对象在父对象的 ivars 被清除后被释放,所以它对例如没有用处。注销 KVO。
猜你喜欢
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多