deallocating,deallocated的使用
我們通常將deallocating
序列結(jié)合takeUntil
使用。達(dá)到當(dāng)對(duì)象銷毀時(shí),序列會(huì)自動(dòng)銷毀的目的。
let vc = LGDetialViewController()
_ = vc.publicOB
.takeUntil(vc.rx.deallocating)
.subscribe(onNext: { (item) in
print("訂閱到 \(item)")
})
self.navigationController?.pushViewController(vc, animated: true)
本文對(duì)deallocating
序列源碼進(jìn)行解析,了解RxSwif
t是如何監(jiān)控一個(gè)對(duì)象的釋放,并給訂閱者發(fā)送消息的。
deallocating源碼解析
想要精確知道一個(gè)對(duì)象的是否銷毀,那就必須掌握對(duì)象dealloc
方法是否執(zhí)行。掌握dealloc
方法是否執(zhí)行,很容易就想到runtime
的方法交換。RxSwift
也是通過(guò)方法交換的方式實(shí)現(xiàn)的嗎?我們進(jìn)入源碼一探究竟。
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)
}
}
}
首先調(diào)用registerMessageInterceptor
創(chuàng)建DeallocatingProxy
對(duì)象. 參數(shù)是dealloc
的Selector
。
dealloc
在ARC下不允許直接@seleteror(dealloc)
,采用NSSelectorFromString("dealloc")
方式解決。
fileprivate func registerMessageInterceptor<T: MessageInterceptorSubject>(_ 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
}
通過(guò)方法名稱,我們推測(cè)RX_ensure_observing
應(yīng)該是我們要分析的重要方法。
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;
}
進(jìn)入方法-(IMP __nullable)ensurePrepared:(id __nonnull)target forObserving:(SEL __nonnull)selector error:(NSErrorParam)error
經(jīng)過(guò)查找,我們找到下面的關(guān)鍵代碼
if (![self swizzleDeallocating:deallocSwizzingTarget error:error]) {
return nil;
}
SWIZZLE_INFRASTRUCTURE_METHOD(
void,
swizzleDeallocating,
,
deallocSelector,
DEALLOCATING_BODY
)
這個(gè)方法用宏實(shí)現(xiàn)的。Swift
下沒(méi)有Load
方法,使用宏定義預(yù)編譯。使用宏可以獲得更高的代碼運(yùn)行效率。
把這個(gè)宏還原成下列方法:
- (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];
}
進(jìn)入-(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);
代碼中通過(guò)method_getImplementation
獲取dealloc
當(dāng)前的IMP originalImplementation
,
然后獲取要替換的IMPimplementationReplacementIMP
,然后使用method_setImplementation
為existingMethodOnTargetClass
Method設(shè)置新的IMP。
到目前為止,我們已經(jīng)驗(yàn)證deallocating
序列是通過(guò)runtime
的方式為交換delloc
的實(shí)現(xiàn),從而實(shí)現(xiàn)對(duì)對(duì)象釋放的監(jiān)控。
當(dāng)對(duì)象調(diào)用dealloc
方法,會(huì)進(jìn)入replacementImplementationGenerator
這個(gè)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
中先執(zhí)行DEALLOCATING_BODY(__VA_ARGS__)
,然后調(diào)用dealloc
交換前的IMP
.
DEALLOCATING_BODY
也是宏實(shí)現(xiàn)的
#define DEALLOCATING_BODY(...) \
id<RXDeallocatingObserver> observer = objc_getAssociatedObject(self, rxSelector); \
if (observer != nil && observer.targetImplementation == thisIMP) { \
[observer deallocating]; \
}
代碼中調(diào)用[observer deallocating]
,觀察者
是關(guān)聯(lián)屬性rxSelector
,我們追溯到registerMessageInterceptor
方法中, 知道序列的觀察者是DeallocatingProxy
那么[observer deallocating]
會(huì)來(lái)到DeallocatingProxy. deallocating()
@objc func deallocating() {
self.messageSent.on(.next(()))
}
DeallocatingProxy
中保存ReplaySubject
序列
let messageSent = ReplaySubject<()>.create(bufferSize: 1)
DeallocatingProxy.deallocating()
中對(duì)messageSent
序列發(fā)送響應(yīng)。
發(fā)送響應(yīng)后,那么就會(huì)有訂閱者來(lái)接收。由于deallocating
和takeUntil
經(jīng)常結(jié)合起來(lái)使用,那么分析一下takeUntil
的源碼,探索一下takeUntil
內(nèi)部是如何接收deallocating
發(fā)送的響應(yīng)非常有必要。想要了解takeUntil
源碼,請(qǐng)查閱RxSwift-TakeUntil源碼分析
至此,deallocating
的源碼分析已經(jīng)完成,deallocated
的實(shí)現(xiàn)與deallocating
基本一致,這里就不再贅述了。
總結(jié):
1.創(chuàng)建序列messageSent
,返回到外界。
2.通過(guò)method-swizzing監(jiān)控對(duì)象的dealloc
3.當(dāng)調(diào)用對(duì)象的dealloc
,為messageSent
發(fā)送響應(yīng).