(二十)RxSwift之析构函数deinit

599 阅读3分钟

swift中存在一个析构函数deinit,在RXSwift中也有类似的函数deallocatingdeallocated,那么他们之间有什么联系吗?

我们通过一个小demo打印一下:

demo

override func viewDidLoad() {
    super.viewDidLoad()

    _ = rx.deallocating.subscribe(onNext: { () in
        print("准备走了-deallocating")
    })
    
    _ = rx.deallocated.subscribe(onNext: { () in
        print("已经走了-deallocated")
    })
}

deinit {
    print("走了-deinit")
}

输出:

准备走了-deallocating
走了-deinit
已经走了-deallocated

我们可以看见在系统的析构函数deinit前后会调用deallocatingdeallocated,这是为什么呢,让我们通过源码来看一下。

deallocating

第一步,deallocating序列的创建

private let deallocSelector = NSSelectorFromString("dealloc")

public var deallocating: Observable<()> {
    return self.synchronized {
        do {
            let proxy: DeallocatingProxy = try self.registerMessageInterceptor(deallocSelector)
            return proxy.messageSent.asObservable()
        }
        catch let e {
            return Observable.error(e)
        }
    }
}

首先通过反射机制拿到系统的析构函数dealloc,然后调用registerMessageInterceptor初始化一个类型为DeallocatingProxyproxy

fileprivate func registerMessageInterceptor<T: MessageInterceptorSubject>(_ selector: Selector) throws -> T {
    let rxSelector = RX_selector(selector)
    let selectorReference = RX_reference_from_selector(rxSelector)
    
    var error: NSError?
    let targetImplementation = RX_ensure_observing(self.base, selector, &error)
    if targetImplementation == nil {
        throw error?.rxCocoaErrorForTarget(self.base) ?? RxCocoaError.unknown
    }

    subject.targetImplementation = targetImplementation!

    return subject
}

然后我们来看一下RX_ensure_observing做了什么事。

IMP __nullable RX_ensure_observing(id __nonnull target, SEL __nonnull selector, NSErrorParam error) {
    __block IMP targetImplementation = nil;
    @synchronized(target) {
        @synchronized([target class]) {
            [[RXObjCRuntime instance] performLocked:^(RXObjCRuntime * __nonnull self) {
                targetImplementation = [self ensurePrepared:target
                                               forObserving:selector
                                                      error:error];
            }];
        }
    }
    return targetImplementation;
}

首先加了锁,然后看到了返回的targetImplementation调用ensurePrepared方法,点击进去看看

-(IMP __nullable)ensurePrepared:(id __nonnull)target forObserving:(SEL __nonnull)selector error:(NSErrorParam)error {
    Method instanceMethod = class_getInstanceMethod([target class], selector);

    if (selector == deallocSelector) {
        Class __nonnull deallocSwizzingTarget = [target class];
        IMP interceptorIMPForSelector = [self interceptorImplementationForSelector:selector forClass:deallocSwizzingTarget];
        if (interceptorIMPForSelector != nil) {
            return interceptorIMPForSelector;
        }

        if (![self swizzleDeallocating:deallocSwizzingTarget error:error]) {
            return nil;
        }

        interceptorIMPForSelector = [self interceptorImplementationForSelector:selector forClass:deallocSwizzingTarget];
        if (interceptorIMPForSelector != nil) {
            return interceptorIMPForSelector;
        }
    }
}

这段代码中包含了一句很重要的信息[self swizzleDeallocating:deallocSwizzingTarget error:error] 由名字就可以看出黑魔法进行了方法交换。

SWIZZLE_INFRASTRUCTURE_METHOD(
    void,
    swizzleDeallocating,
    ,
    deallocSelector,
    DEALLOCATING_BODY
)

点进来,代码很少啊,一个宏和几个参数,那我们来看看这个宏做了什么? 我们将这段宏还原成下面的代码,方便阅读

-(BOOL)swizzleDeallocating:(Class __nonnull)class error:(NSError *)error{
    
    SEL selector = NSSelectorFromString(@"delloc");
    __unused SEL rxSelector = NSSelectorFromString(@"_RX_namespace_delloc");
    
    IMP (^newImplementationGenerator)(void) = ^() {
        __block IMP thisIMP = nil;
        id newImplementation = ^void(__unsafe_unretained id self DECLARE_ARGUMENTS(__VA_ARGS__)) {
            body(__VA_ARGS__)
                                                                                                                         
            struct objc_super superInfo = {
                .receiver = self,
                .super_class = class_getSuperclass(class)
            };
                                             
            void (*msgSend)(struct objc_super *, SEL DECLARE_ARGUMENTS(__VA_ARGS__))
                = (__typeof__(msgSend))objc_msgSendSuper;
            @try {
              return msgSend(&superInfo, selector ARGUMENTS(__VA_ARGS__));
            }
            @finally { invoked_body(__VA_ARGS__) }
        };
              
        thisIMP = imp_implementationWithBlock(newImplementation);
        return thisIMP;
    };
              
    IMP (^replacementImplementationGenerator)(IMP) = ^(IMP originalImplementation) {
        __block void (*originalImplementationTyped)(__unsafe_unretained id, SEL DECLARE_ARGUMENTS(__VA_ARGS__) )
            = (__typeof__(originalImplementationTyped))(originalImplementation);
              
        __block IMP thisIMP = nil;
        id implementationReplacement = ^void(__unsafe_unretained id self DECLARE_ARGUMENTS(__VA_ARGS__) ) {
            body(__VA_ARGS__)
            @try {
                return originalImplementationTyped(self, selector ARGUMENTS(__VA_ARGS__));
            }
            @finally { invoked_body(__VA_ARGS__) }
        };
              
        thisIMP = imp_implementationWithBlock(implementationReplacement);
        return thisIMP;
    };
                                                 
    return [self ensureSwizzledSelector:selector
                                ofClass:class
             newImplementationGenerator:newImplementationGenerator
     replacementImplementationGenerator:replacementImplementationGenerator
                                  error:error];
 }

接下来会来到returnensureSwizzledSelector方法,

-(BOOL)ensureSwizzledSelector:(SEL __nonnull)selector
                      ofClass:(Class __nonnull)class
   newImplementationGenerator:(IMP(^)(void))newImplementationGenerator
replacementImplementationGenerator:(IMP (^)(IMP originalImplementation))replacementImplementationGenerator
                        error:(NSErrorParam)error {
                        
    IMP originalImplementation = method_getImplementation(existingMethodOnTargetClass);
    ALWAYS(originalImplementation != nil, @"Method must exist.");
    IMP implementationReplacementIMP = replacementImplementationGenerator(originalImplementation);
    ALWAYS(implementationReplacementIMP != nil, @"Method must exist.");
    IMP originalImplementationAfterChange = method_setImplementation(existingMethodOnTargetClass, implementationReplacementIMP);
    ALWAYS(originalImplementation != nil, @"Method must exist.");
    
    return YES;
}

通过 method_setImplementationdeallocIMP指向代码块replacementImplementationGenerator中。所以当系统触发了dealloc函数,就会来到块replacementImplementationGenerator

IMP (^replacementImplementationGenerator)(IMP) = ^(IMP originalImplementation) {
    __block void (*originalImplementationTyped)(__unsafe_unretained id, SEL DECLARE_ARGUMENTS(__VA_ARGS__) )
        = (__typeof__(originalImplementationTyped))(originalImplementation);

    __block IMP thisIMP = nil;
    id implementationReplacement = ^void(__unsafe_unretained id self DECLARE_ARGUMENTS(__VA_ARGS__) ) {
        body(__VA_ARGS__)
        @try {
            return originalImplementationTyped(self, selector ARGUMENTS(__VA_ARGS__));
        }
        @finally { invoked_body(__VA_ARGS__) }
    };
          
    thisIMP = imp_implementationWithBlock(implementationReplacement);
    return thisIMP;
};

当完成一系列操作以后会来到{ invoked_body(__VA_ARGS__) },进来的时候传了4个参数,让我们看最后一个参数DEALLOCATING_BODY

#define DEALLOCATING_BODY(...)                                                        \
    id<RXDeallocatingObserver> observer = objc_getAssociatedObject(self, rxSelector); \
    if (observer != nil && observer.targetImplementation == thisIMP) {                \
        [observer deallocating];                                                      \
    }

我们看见他拿到了替换后的方法deallocating,当系统调用delloc的时候就会调用deallocating

@objc func deallocating() {
    self.messageSent.on(.next(()))
}
deinit {
    self.messageSent.on(.completed)
}

DeallocatingProxy中保存ReplaySubject序列,并在deallocating()进行发送响应。 这就是为什么deallocating会在deinit前面响应了。

deallocated

在来看一下deallocated

public var deallocated: Observable<Void> {
    return self.synchronized {
        if let deallocObservable = objc_getAssociatedObject(self.base, &deallocatedSubjectContext) as? DeallocObservable {
            return deallocObservable._subject
        }

        let deallocObservable = DeallocObservable()

        objc_setAssociatedObject(self.base, &deallocatedSubjectContext, deallocObservable, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        return deallocObservable._subject
    }
}
fileprivate final class DeallocObservable {
    let _subject = ReplaySubject<Void>.create(bufferSize:1)

    init() {
    }

    deinit {
        self._subject.on(.next(()))
        self._subject.on(.completed)
    }
}

内部初始化了ReplaySubject,当调用系统函数deinit后,就会发送响应。

总结:

RxSwift中提供了两个和deinit有关的序列,观察dealloc的调用,其中deallocating内部替换了原生的dealloc方法从而达到监听dealloc的调用 这里并不是交换方法,而是在replacementImplementationGenerator代码块中先保留了dealloc的函数地址,再通过imp_implementationWithBlock设置dealloc的IMP,指向了replacementImplementationGenerator代码块 调用dealloc方法就会调用了代码块,在代码块内部通过body函数调用了deallocating方法,之后执行代码块中保留的原dealloc函数。