Метод обратного вызова перед освобождением любого объекта

#iphone #objective-c #cocoa-touch #cocoa

#iPhone #objective-c #cocoa-touch #cocoa

Вопрос:

Есть ли какой-либо способ вызвать метод перед освобождением любого объекта класса NSObject.

или

Возможно ли написать пользовательский метод dealloc для класса NSObject, чтобы
мы могли вызывать любой метод перед освобождением этого объекта?

Поскольку сборщик мусора недоступен для iPhone, я хочу создать небольшую платформу, которая обрабатывает утечку памяти во время выполнения и создает файлы журнала для утечек (я знал, что есть инструмент, который идентифицирует утечки, но все еще для исследований и разработок и не хочет внедрять алгоритм сборщика мусора).

Мы пытаемся поддерживать список выделенных объектов.

например:

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

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

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

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


[objects setValue: allocatedMemoryAddress forKey: veribaleAddress];
  

но когда какой-либо объект освобождается, я хочу сначала посмотреть, присутствует ли адрес этого объекта в словаре или нет. Если адрес присутствует, удалите его из словаря.

Пожалуйста, подскажите мне, возможно это или нет.

Спасибо

Комментарии:

1. Вы получите лучшие ответы, если расскажете нам, чего вы пытаетесь достичь.

2. Возможно, вы смогли бы использовать swizzle -[NSObject dealloc] , но это, как правило, плохая идея ™. Чего именно вы пытаетесь достичь?

3. Я не уверен, правильно ли я вас понимаю. Вы хотите вызвать метод в dealloc или перед dealloc. Я полагаю, вы знаете, что вы никогда не отправляете сообщение об освобождении напрямую. Вместо этого метод dealloc объекта вызывается косвенно через метод протокола release NSObject (если сообщение о выпуске приводит к тому, что счетчик сохранения получателя становится равным 0)

4. Всем привет, я снова отредактировал свой вопрос. пожалуйста, проверьте это.

5. а) вам не следует этого делать б) если вы все еще убеждены, что это того стоит, вашей реализации потребуется значительный редизайн в) вам не следует этого делать

Ответ №1:

Вот примерная суть, показывающая, как использовать dealloc метод, если это то, что вам нужно. Основная часть кода:

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

Как говорит Бавариус, это темная магия, и я бы никогда не использовал ее в производстве.

Комментарии:

1. 1 за то, что я первым подробно описал правильный способ сделать это («правильный» в том смысле, что так можно подойти к реализации чего-то, что никогда не должно существовать)

2. 1 повторяю ваши с Джастином оговорки, но swizzling является законным инструментом в редких случаях — я думаю, именно так реализован KVO.

3. Кстати, swizzledDealloc необходимо вызвать исходный dealloc, иначе объект фактически не будет освобожден.

4. Я настроил код swizzelDealloc следующим образом, поскольку мне нужен обратный вызов метода для каждого объекта, который получает dealloc, поэтому я использую метод dealloc класса NSObject, для этого я создаю категорию NSObject и добавляю в нее метод swizzelDealloc следующим образом .. ‘-(void)swizzledDealloc’ { //вызов метода обработчика… classplaceDeallocated([self class]); [self dealloc];//вызовите реализацию метода dealloc по умолчанию .. classReplaceDeallocated([self class]); }’

5. I’m f… Месяц назад я проверил значение dealloc для UIView, теперь я понимаю, что UIViews случайным образом освобождается при вызове dealloc. Я облажался, должен сказать своему боссу, что моя магия больше не работает… Я доказываю, что swizzle the 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 или что-то еще, что приводит к путанице с количеством сохранений. Я бы не рассчитывал на то, что смогу использовать рассматриваемый объект во время обратного вызова, но его адрес все равно должен быть в порядке, и это то, что вам, похоже, нужно.

Комментарии:

1. Связанные объекты освобождаются ПОСЛЕ очистки ivar родительского объекта, поэтому это бесполезно, например, для отмены регистрации KVO.