objective-cmsgsend

Send the message objc_msgSend(class,@selector(dealloc)) to release the object, why is it wrong to access the object pointer?


The code is under ARC. When I delete the code NSObject* objc = (NSObject*)object; the program runs fine, but I didn't have access to the pointer objc. When I keep the code NSObject* objc = (NSObject*)object; I am prompted EXC_BAD_ACCESS (code=1, address=0x20). Is the system accessing the objc pointer after the block function body ends?

-(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


Solution

  • Note: This answer is being directly typed in, your code has not been tested, indeed no code has been tested. Therefore that the issues below are causing your issues is being inferred.

    There area number of issues with your design:

    You appear to be trying to call your removeAllTargetWithSuffixKey: method when a particular object is destroyed (appear as you swizzle [and can only swizzle] the class but are using the hash of a particular object). A better way to do this avoiding swizzling is to use associated objects.

    The runtime function objc_setassociatedobject() allows you to attach an object to a particular instance of another object and have that object be destroyed automatically when its host is destroyed (use an objc_AssociationPolicy of OBJC_ASSOCIATION_RETAIN).

    Design a class which has an instance property of your required hash value and a dealloc method which calls your removeAllTargetWithSuffixKey: then rather than swizzle the class simply create and associate an instance of your class with the target object.

    HTH