原文 : 与佳期的我的博客(gonghonglou.com)git
If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its dealloc method. Otherwise, you should call this method or removeObserver:name:object: before observer or any object specified in addObserverForName:object:queue:usingBlock: or addObserver:selector:name:object: is deallocated. You shouldn't use this method to remove all observers from a long-lived object, because your code may not be the only code adding observers that involve the object. The following example illustrates how to unregister someObserver for all notifications for which it had previously registered. This is safe to do in the dealloc method, but should not otherwise be used (use removeObserver:name:object: instead).github
这是苹果官方文档的说法,也就是说 iOS9 以前,当一个对象添加了 notification 以后,若是 dealloc 的时候,仍然持有 notification,就会出现 NSNotification 类型的 Crash。bash
防御方案很简单就是 Hook NSObject 的 dealloc 方法,在对象真正 dealloc 以前先调用一下移除操做:app
[[NSNotificationCenter defaultCenter] removeObserver:self];
复制代码
固然,为了避免必要的操做,咱们应该只在添加了通知的对象里去执行移除。一样的,Hook NSNotificationCenter 的 - (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
方法,添加一个标记,在 dealloc 方法里根据这个标记来执行移除操做。this
代码实现,NSNotificationCenter+GHLCrashGuard 分类里添加标记:spa
@implementation NSNotificationCenter (GHLCrashGuard)
+ (void)load {
if ([UIDevice currentDevice].systemVersion.doubleValue < 9.0) {
[self jr_swizzleMethod:@selector(addObserver:selector:name:object:) withMethod:@selector(ghl_addObserver:selector:name:object:) error:nil];
}
}
- (void)ghl_addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject {
[self ghl_addObserver:observer selector:aSelector name:aName object:anObject];
objc_setAssociatedObject(observer, "addObserverFlag", @YES, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
复制代码
NSObject+GHLCrashGuard 分类里 Hook dealloc 方法:code
+ (void)load {
[self jr_swizzleMethod:NSSelectorFromString(@"dealloc") withMethod:@selector(ghl_dealloc) error:nil];
}
- (void)ghl_dealloc {
if ([UIDevice currentDevice].systemVersion.doubleValue < 9.0) {
[[GHLNotificationCenterManager sharedInstance] handleObjectRemoveObserver:self];
}
[self ghl_dealloc];
}
复制代码
GHLNotificationCenterManager 的 handleObjectRemoveObserver: 方法实现:server
- (void)handleObjectRemoveObserver:(__unsafe_unretained id)object {
NSString *addObserver = objc_getAssociatedObject(object, "addObserverFlag");
if ([addObserver boolValue]) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
复制代码
Demo 地址:GHLCrashGuard:GHLCrashGuard/Classes/NSNotificationCenter对象
小白出手,请多指教。如言有误,还望斧正!ci
转载请保留原文地址:gonghonglou.com/2019/07/08/…