1

代码在 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;
}

在此处输入图像描述

4

2 回答 2

2

注意:这个答案是直接输入的,你的代码没有经过测试,确实没有代码经过测试。因此,正在推断以下问题导致您的问题。

您的设计存在许多问题:

  • dealloc不建议搅拌。该dealloc方法在销毁对象的过程中由系统自动调用,因此不恰当地使用部分销毁的对象(无论可能是什么)可能会导致问题 - 正如您所发现的!
  • 您正在使用 ARC,其中“dealloc 的实现,[不应] 调用超类的实现”。但是,您的块会执行此操作。
  • 该变量objc未使用。但是,默认情况下,局部变量具有该属性strong,因此您在销毁过程中创建对对象的强引用。块以这种方式所做的任何强引用都将在块完成后由 ARC 释放,这几乎肯定不是你的错误所表明的那样好。

removeAllTargetWithSuffixKey:当特定对象被销毁时,您似乎正在尝试调用您的方法(出现在您调配 [并且只能调配]但正在使用hash特定对象的情况下)。避免混杂的更好方法是使用关联对象

运行时函数objc_setassociatedobject()允许您将对象附加到另一个对象的特定实例,并在其宿主被销毁时自动销毁该对象(使用objc_AssociationPolicyof OBJC_ASSOCIATION_RETAIN)。

设计一个类,该类具有所需hash值的实例属性和dealloc调用removeAllTargetWithSuffixKey:then 而不是 swizzle 类的方法,只需创建类的实例并将其与目标对象关联即可。

高温高压

于 2018-12-15T10:40:08.587 回答
0

是的,它在方法结束后访问指针。如果这是在 ARC 下编译的,那么 objc 是一个“强”引用。但是,您正在制造dealloc方法的实现,因此在对象已经被解除分配时保留该对象,因此对它进行强引用为时已晚。您的实现将调用 super,它实际上应该释放对象,然后 ARC 将释放 objc 值,但它已经消失了,因为它是接收者,即如果您正在编写普通的 dealloc 方法,则为“self”。

ARC 永远不会在常规的 dealloc 方法中保留 self ,但这就是你正在做的事情。“对象”值是同一个指针,但显式为 __unsafe_unretained,因此您应该直接使用它。如果有帮助,您可以将块键入为 NSObject* 而不是 id,但这无关紧要。或者你可以让你的 objc 值也 __unsafe_unretained 所以 ARC 不理会它。您不希望 ARC 以任何方式触及块内的“self”值,因为在这种情况下您将绕过 ARC。

无论如何,一旦你在一个对象的 dealloc 方法中,永远不要保留/释放/自动释放 self 指针——它会以崩溃告终。例如,从 dealloc 调用方法并将引用传递给 self 是一个禁忌。如果您正在玩这些类型的运行时游戏,您需要非常小心,并准确了解 ARC 在做什么。

于 2018-12-16T22:33:35.660 回答