Отправьте сообщение objc_msgSend (class, @ selector (dealloc)), чтобы освободить объект. Почему неправильно получить доступ к указателю объекта? - PullRequest
0 голосов
/ 14 декабря 2018

Код находится под ARC.Когда я удаляю код NSObject* objc = (NSObject*)object;, программа работает нормально, но у меня не было доступа к указателю objc.Когда я сохраняю код NSObject* objc = (NSObject*)object;, мне предлагается EXC_BAD_ACCESS (code=1, address=0x20).Получает ли система доступ к указателю objc после завершения тела функции блока?

-(void)resetDeallocMethodWithInstance:(NSObject*)obj
{
    Class targetClass = obj.class;
    @synchronized (swizzledClasses()) {
        NSString *className = NSStringFromClass(obj.class);
        if ([swizzledClasses() containsObject:className]) return;
        SEL deallocSel = sel_registerName("dealloc");
        __block void (*deallocBlock)(__unsafe_unretained id, SEL) = NULL;
        id block = ^(__unsafe_unretained id object){
            NSObject* objc = (NSObject*)object;
            NSUInteger hash = ((NSObject*)object).hash;
            [self removeAllTargetWitSuffixKey:[NSString stringWithFormat:@"%lu",(unsigned long)hash]];
            if (deallocBlock == NULL) {
                struct objc_super superInfo = {
                    .receiver = object,
                    .super_class = class_getSuperclass(targetClass)
                };
                void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
                msgSend(&superInfo, deallocSel);
            } else {
                deallocBlock(object, deallocSel);
            }
        };
        IMP blockImp = imp_implementationWithBlock(block);
        if (!class_addMethod(obj.class, deallocSel, blockImp, "v@:")) {
            Method deallocMethod = class_getInstanceMethod(obj.class, deallocSel);
            deallocBlock = (__typeof__(deallocBlock))method_getImplementation(deallocMethod);
            deallocBlock = (__typeof__(deallocBlock))method_setImplementation(deallocMethod, blockImp);
        }
        [swizzledClasses() addObject:className];
    }
    return;
}

введите описание изображения здесь

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Да, он обращается к указателю после завершения метода.Если это компилируется в ARC, то objc является «сильной» ссылкой.Однако вы фабрикуете реализацию метода dealloc и, таким образом, сохраняете объект, когда он уже будет освобожден, поэтому уже слишком поздно ссылаться на него.Ваша реализация будет вызывать super, который должен на самом деле освободить объект, а затем ARC собирается освободить значение objc, но оно уже пропало, так как это получатель, то есть «self», если вы писали обычный метод dealloc.

ARC никогда не сохранит себя в обычном методе dealloc, но это то, что вы эффективно делаете.Значение «object» - это тот же указатель, но явно __unsafe_unretained, поэтому вы должны просто использовать это напрямую.Вы можете напечатать блок как NSObject * вместо id, если это поможет, но это не должно иметь значения.Или вы можете сделать ваше значение objc также __unsafe_unretained, так что ARC оставляет его в покое.Вы не хотите, чтобы ARC каким-либо образом касался значения «self» внутри блока, поскольку в этом случае вы обходите ARC назад.

В любом случае, если вы находитесь в методе dealloc объекта,никогда не сохраняйте / не освобождайте / не запускайте авто-указатель самостоятельно - это приведет к сбою.Например, вызов метода из dealloc и передача ссылки на себя - нет-нет.Вы должны быть очень осторожны с этим и точно понимать, что делает ARC, если вы играете в такие игры во время выполнения.

0 голосов
/ 15 декабря 2018

Примечание. Этот ответ вводится напрямую, ваш код проверен на , а не , действительно проверен нет код.Поэтому выявляются следующие проблемы, из-за которых возникают проблемы.

Существует ряд проблем с вашим дизайном:

  • Swizzling dealloc не рекомендуется.Метод dealloc автоматически вызывается системой, когда она находится в процессе уничтожения объекта, поэтому использование частично уничтоженного объекта ненадлежащим образом (что бы это ни было) может привести к проблемам - как вы уже обнаружили!
  • Вы используете ARC, при котором «реализация dealloc [не должна вызывать реализацию суперкласса» * .Однако ваш блок делает это.
  • Переменная objc не используется.Однако по умолчанию локальная переменная имеет атрибут strong, поэтому вы создаете сильную ссылку на объект в процессе уничтожения.Любая сильная ссылка, сделанная таким образом блоком, будет освобождена ARC, когда блок завершится, это почти наверняка не очень хорошо, как показывает ваша ошибка.

Вы, кажется, пытаетесь позвонить вашему removeAllTargetWithSuffixKey: метод, когда конкретный объект уничтожается ( появляется , когда вы кружитесь [и можете только кружить] класс , но используете hash определенного объекта).Лучшим способом избежать этого является использование связанных объектов .

Функция времени выполнения objc_setassociatedobject() позволяет вам прикрепить объект к определенному экземпляру другогообъект, и этот объект будет уничтожен автоматически при уничтожении его хоста (используйте objc_AssociationPolicy из OBJC_ASSOCIATION_RETAIN).

Создайте класс, у которого есть свойство экземпляра с требуемым значением hash и dealloc метод, который вызывает ваш removeAllTargetWithSuffixKey:, а затем вместо того, чтобы свистеть класс, просто создайте и свяжите экземпляр вашего класса с целевым объектом.

HTH

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...