发送消息objc_msgSend(class,@ selector(dealloc))释放对象,为什么访问对象指针出错?

时间:2018-12-14 08:33:27

标签: objective-c msgsend

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

enter image description here

2 个答案:

答案 0 :(得分:2)

注意:此答案是直接输入的,您的代码未经过测试,实际上已受过测试。因此,可以推断出以下问题正在导致您的问题。

您的设计存在许多问题:

  • 不推荐使用deallocdealloc方法在销毁对象的过程中会自动被系统调用,例如,不当使用部分销毁的对象(无论可能如何)都可能导致问题-如您所见!
  • 您正在使用"an implementation of dealloc, [should] not invoke the superclass’s implementation"下的ARC。但是,您的代码块会这样做。
  • 变量objc未使用。但是,默认情况下,局部变量具有属性strong,因此您要在销毁过程中创建对对象的强引用。块完成后,ARC会释放该块以这种方式做出的任何强引用,几乎可以肯定这不是您的错误所表明的。

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

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

设计一个类,该类具有您所需的hash值的实例属性和一个dealloc方法,该方法调用您的removeAllTargetWithSuffixKey:,然后不必烦恼该类,只需创建并关联您的实例类与目标对象。

HTH

答案 1 :(得分:0)

是的,方法结束后它正在访问指针。如果在ARC下进行编译,则objc是“强”引用。但是,您正在构造 dealloc 方法的实现,并且在对象已经要被分配时也保留了该对象,因此对它进行强大的引用为时已晚。您的实现将调用super,它实际上应该取消分配对象,然后ARC将释放objc值,但是由于它是接收者,所以已经消失了,如果您正在编写普通的dealloc方法,则为“ self”。 / p>

ARC永远不会将自己保留在常规的dealloc方法中,但这就是您正在有效地做的事情。 “对象”值是相同的指针,但是显式是__unsafe_unretained,因此您应该直接使用它。如果有帮助,您可以将块键入NSObject *而不是id,但这没关系。或者,您也可以将objc值也设置为__unsafe_unretained,以便ARC不用管它。您不希望ARC以任何方式触摸块内的“自我”值,因为在这种情况下,您将绕过ARC的背面。

无论如何,一旦进入对象的dealloc方法,就永远不要保留/释放/自动释放自指针,否则将导致崩溃。例如,从dealloc调用方法并将引用传递给self是不可以的。您需要对此非常小心,并且如果您正在玩这些类型的运行时游戏,则必须确切了解ARC在做什么。