Найти, где объект хранится с помощью ARC

У меня есть объект, который сохраняется более чем необходимо (скорее всего, из-за свойства strong вместо weak). Большая база кода, поэтому трудно найти, где.

Как найти все строки, в которых этот объект сохраняется при использовании ARC?

Если бы я не использовал ARC, я бы мог просто переопределить retain и проверить, откуда он вызвал. Могу ли я сделать что-то подобное с ARC?

Ответ 1

Чтобы отслеживать рост приложения, Heapshot Analysis оказался очень эффективным. Он будет захватывать как истинные утечки, так и аккрецию памяти, где распределения не учитываются утечками.

Вы можете увидеть все события сохранения/выпуска и их обратную трассировку, используя инструмент Allocations. Нажмите маленькую (i) кнопку на инструменте "Распределения" и включите "Запись отсчетов". Включение "Только отслеживать активные распределения" уменьшает объем данных, собранных Инструментами, делая его более быстрым (и мертвые распределения в этом контексте не очень полезны, но могут быть и в других).

С этим вы можете погрузиться в любое распределение (щелкнув по правой стрелке в поле адреса), увидеть все события сохранения/выпуска и посмотреть, где именно они произошли.

enter image description here

Ответ 2

Мне удалось найти оскорбление retain, выполнив следующие действия:

  • Временно добавить -fno-objc-arc к классу компилятора объекта. для отключения ARC для этого класса.
  • Временно переопределить retain (просто вызвать super) и поставить на него контрольную точку.
  • Отлаживать и проверять стек вызовов каждый раз, когда вызывается retain.

Ответ 3

На прошлой неделе я помогал друзьям отлаживать утечки в проекте ARC. Некоторые советы:

1/Создание профилирования и запуск инструментов с обнаружением утечки. Затем исследуйте выделенные в данный момент объекты, найдите нужный объект (вы можете отсортировать их по имени) и загляните в историю сохранения/выпуска. Обратите внимание, что счет сохранения не очень помогает с ARC. Вы должны проверять его вручную шаг за шагом.

Попробуйте прокомментировать весь код, который может быть источником утечки, а затем раскомментировать его шаг за шагом.

2/Поместите a NSLog в ваш init и в dealloc, чтобы наблюдать, когда объект был создан и уничтожен.

3/Не смотрите только на определения свойств, смотрите, если средства настройки свойств выполняются вручную. Я нашел проблему в проекте моих друзей следующим образом:

@property (weak, nonatomic) id<...> delegate;

@interface ... {
    id<...&gt _delegate;
}

@synthesize delegate = _delegate;

- (void)setDelegate(id<...>)delegate {
    _delegate = delegate;  //with ARC this retains the object!
}

Ответ 4

Это решение было несколько полезно для меня. Он в основном использует метод swizzling для трюков компилятора ARC, думая, что вы не переопределяете сохранение и освобождение.

    + (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    Class cls = [self class];

    // When swizzling a class method, use the following:
    // Class class = object_getClass((id)self);

    SEL originalSelector1 = NSSelectorFromString(@"retain");
    SEL swizzledSelector1 = NSSelectorFromString(@"myretain");

    SEL originalSelector2 = NSSelectorFromString(@"release");
    SEL swizzledSelector2 = NSSelectorFromString(@"myrelease");

    Method originalMethod1 = class_getInstanceMethod(cls, originalSelector1);
    Method swizzledMethod1 = class_getInstanceMethod(cls, swizzledSelector1);
    Method originalMethod2 = class_getInstanceMethod(cls, originalSelector2);
    Method swizzledMethod2 = class_getInstanceMethod(cls, swizzledSelector2);

    BOOL didAddMethod1 =
    class_addMethod(cls,
                    originalSelector1,
                    method_getImplementation(swizzledMethod1),
                    method_getTypeEncoding(swizzledMethod1));

    if (didAddMethod1) {
        class_replaceMethod(cls,
                            swizzledSelector1,
                            method_getImplementation(originalMethod1),
                            method_getTypeEncoding(originalMethod1));
    } else {
        method_exchangeImplementations(originalMethod1, swizzledMethod1);
    }

    BOOL didAddMethod2 =
    class_addMethod(cls,
                    originalSelector2,
                    method_getImplementation(swizzledMethod2),
                    method_getTypeEncoding(swizzledMethod2));

    if (didAddMethod2) {
        class_replaceMethod(cls,
                            swizzledSelector2,
                            method_getImplementation(originalMethod2),
                            method_getTypeEncoding(originalMethod2));
    } else {
        method_exchangeImplementations(originalMethod2, swizzledMethod2);
    }


});
}

-(id)myretain {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSLog(@"tracking retain now %d",(int)[self performSelector:NSSelectorFromString(@"retainCount")]);
SEL selector = NSSelectorFromString(@"myretain");
return [self performSelector:selector withObject:nil];
#pragma clang diagnostic pop
}

-(id)myrelease {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSLog(@"tracking release now %d",(int)[self performSelector:NSSelectorFromString(@"retainCount")]);

SEL selector = NSSelectorFromString(@"myrelease");
return [self performSelector:selector withObject:nil];
#pragma clang diagnostic pop

}

Ответ 5

Если вы используете ARC, вы никогда не получите возможность добавить сохранение,

secreenshot1

и если вы преобразовали проект в ARC, используя нижеприведенный вариант, вам будет предложено с ошибкой

screenshot2

Если вы установили свойство как strong, вы должны выделить объект один раз через весь проект, например. self.yourobject = [[NSMutableArray alloc]init];. Для этого нет ярлыка.