deallocating,deallocated的使用
我们通常将deallocating
序列结合takeUntil
使用。达到当对象销毁时,序列会自动销毁的目的。
let vc = LGDetialViewController()
_ = vc.publicOB
.takeUntil(vc.rx.deallocating)
.subscribe(onNext: { (item) in
print("订阅到 \(item)")
})
self.navigationController?.pushViewController(vc, animated: true)
本文对deallocating
序列源码进行解析,了解RxSwif
t是如何监控一个对象的释放,并给订阅者发送消息的。
deallocating源码解析
想要精确知道一个对象的是否销毁,那就必须掌握对象dealloc
方法是否执行。掌握dealloc
方法是否执行,很容易就想到runtime
的方法交换。RxSwift
也是通过方法交换的方式实现的吗?我们进入源码一探究竟。
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)
}
}
}
首先调用registerMessageInterceptor
创建DeallocatingProxy
对象. 参数是dealloc
的Selector
。
dealloc
在ARC下不允许直接@seleteror(dealloc)
,采用NSSelectorFromString("dealloc")
方式解决。
fileprivate func registerMessageInterceptor(_ selector: Selector) throws -> T {
......
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;
// Target is the second object that needs to be synchronized to TRY to make sure other swizzling framework
// won't do something in parallel.
// Even though this is too fine grained locking and more coarse grained locks should exist, this is just in case
// someone calls this method directly without any external lock.
@synchronized(target) {
// The only other resource that all other swizzling libraries have in common without introducing external
// dependencies is class object.
//
// It is polite to try to synchronize it in hope other unknown entities will also attempt to do so.
// It's like trying to figure out how to communicate with aliens without actually communicating,
// save for the fact that aliens are people, programmers, authors of swizzling libraries.
@synchronized([target class]) {
[[RXObjCRuntime instance] performLocked:^(RXObjCRuntime * __nonnull self) {
targetImplementation = [self ensurePrepared:target
forObserving:selector
error:error];
}];
}
}
return targetImplementation;
}
进入方法-(IMP __nullable)ensurePrepared:(id __nonnull)target forObserving:(SEL __nonnull)selector error:(NSErrorParam)error
经过查找,我们找到下面的关键代码
if (![self swizzleDeallocating:deallocSwizzingTarget error:error]) {
return nil;
}
SWIZZLE_INFRASTRUCTURE_METHOD(
void,
swizzleDeallocating,
,
deallocSelector,
DEALLOCATING_BODY
)
这个方法用宏实现的。Swift
下没有Load
方法,使用宏定义预编译。使用宏可以获得更高的代码运行效率。
把这个宏还原成下列方法:
- (BOOL)swizzleDeallocating:(Class __nonnull)class error:(NSErrorParam)error
{
SEL selector = deallocSelector;
__unused SEL rxSelector = RX_selector(selector);
IMP (^newImplementationGenerator)(void) = ^() {
__block IMP thisIMP = nil;
id newImplementation = ^void(__unsafe_unretained id self DECLARE_ARGUMENTS(__VA_ARGS__)) {
DEALLOCATING_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 { NO_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__) ) {
DEALLOCATING_BODY(__VA_ARGS__)
@try {
return originalImplementationTyped(self, selector ARGUMENTS(__VA_ARGS__));
}
@finally { NO_BODY(__VA_ARGS__) }
};
thisIMP = imp_implementationWithBlock(implementationReplacement);
return thisIMP;
};
return [self ensureSwizzledSelector:selector
ofClass:class
newImplementationGenerator:newImplementationGenerator
replacementImplementationGenerator:replacementImplementationGenerator
error:error];
}
进入-(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);
IMP implementationReplacementIMP = replacementImplementationGenerator(originalImplementation);
IMP originalImplementationAfterChange = method_setImplementation(existingMethodOnTargetClass, implementationReplacementIMP);
代码中通过method_getImplementation
获取dealloc
当前的IMP originalImplementation
,
然后获取要替换的IMPimplementationReplacementIMP
,然后使用method_setImplementation
为existingMethodOnTargetClass
Method设置新的IMP。
到目前为止,我们已经验证deallocating
序列是通过runtime
的方式为交换delloc
的实现,从而实现对对象释放的监控。
当对象调用dealloc
方法,会进入replacementImplementationGenerator
这个IMP
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__) ) {
DEALLOCATING_BODY(__VA_ARGS__)
@try {
return originalImplementationTyped(self, selector ARGUMENTS(__VA_ARGS__));
}
@finally { NO_BODY(__VA_ARGS__) }
};
thisIMP = imp_implementationWithBlock(implementationReplacement);
return thisIMP;
};
IMP
中先执行DEALLOCATING_BODY(__VA_ARGS__)
,然后调用dealloc
交换前的IMP
.
DEALLOCATING_BODY
也是宏实现的
#define DEALLOCATING_BODY(...) \
id observer = objc_getAssociatedObject(self, rxSelector); \
if (observer != nil && observer.targetImplementation == thisIMP) { \
[observer deallocating]; \
}
代码中调用[observer deallocating]
,观察者
是关联属性rxSelector
,我们追溯到registerMessageInterceptor
方法中, 知道序列的观察者是DeallocatingProxy
那么[observer deallocating]
会来到DeallocatingProxy. deallocating()
@objc func deallocating() {
self.messageSent.on(.next(()))
}
DeallocatingProxy
中保存ReplaySubject
序列
let messageSent = ReplaySubject<()>.create(bufferSize: 1)
DeallocatingProxy.deallocating()
中对messageSent
序列发送响应。
发送响应后,那么就会有订阅者来接收。由于deallocating
和takeUntil
经常结合起来使用,那么分析一下takeUntil
的源码,探索一下takeUntil
内部是如何接收deallocating
发送的响应非常有必要。想要了解takeUntil
源码,请查阅RxSwift-TakeUntil源码分析
至此,deallocating
的源码分析已经完成,deallocated
的实现与deallocating
基本一致,这里就不再赘述了。
总结:
1.创建序列messageSent
,返回到外界。
2.通过method-swizzing监控对象的dealloc
3.当调用对象的dealloc
,为messageSent
发送响应.