iOS-简单创建MLFinder并学习
1:创建工程的目录结构
1.1工程的目录结构
文章图片
工程目录结构.jpg 1.2 工程思维导图
文章图片
工程类图结构 2:原理解释
MLFinder的原理就是在viewcontroller返回时候(pop)检测当前的viewcontroller是否还有能力调用指定的willDealloc的方法。
【iOS-简单创建MLFinder并学习】总结成一句话:利用runtime发送消息的时候,receiver可以为nil,如[nil msg]。不会奔溃。
3:运行流程
文章图片
运行流程图 4:源码如下
4.1 NSObject+MLFinder.m
#import "NSObject+MLFinder.h"
#import
#import
const void *const kLatestSenderKey = &kLatestSenderKey;
@implementation NSObject (MLFinder)
+ (void)swizzleSEL:(SEL)originalSEL withSEL:(SEL)swizzledSEL {
Class class = [self class];
Method originalMethod = class_getInstanceMethod(class, originalSEL);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL);
BOOL didAddMethod =
class_addMethod(class,
originalSEL,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSEL,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (BOOL)willDealloc {__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong id strongSelf = weakSelf;
[strongSelf assertNotDealloc];
});
return YES;
}
- (void)assertNotDealloc {
NSLog(@"\n\n================assertNotDeallocassertNotDealloc================\n\n");
}
@end
4.2 UINavigationController+MLFinder.m
#import "UINavigationController+MLFinder.h"
#import "NSObject+MLFinder.h"
#import
static const void *const kPoppedDetailVCKey = &kPoppedDetailVCKey;
@implementation UINavigationController (MLFinder)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleSEL:@selector(popViewControllerAnimated:) withSEL:@selector(swizzled_popViewControllerAnimated:)];
});
}
- (UIViewController *)swizzled_popViewControllerAnimated:(BOOL)animated {
UIViewController *poppedViewController = [self swizzled_popViewControllerAnimated:animated];
if (!poppedViewController) {
return nil;
}//// Detail VC in UISplitViewController is not dealloced until another detail VC is shown
//if (self.splitViewController &&
//self.splitViewController.viewControllers.firstObject == self &&
//self.splitViewController == poppedViewController.splitViewController) {
//objc_setAssociatedObject(self, kPoppedDetailVCKey, poppedViewController, OBJC_ASSOCIATION_RETAIN);
//return poppedViewController;
//}// VC is not dealloced until disappear when popped using a left-edge swipe gesture
extern const void *const kHasBeenPoppedKey;
objc_setAssociatedObject(poppedViewController, kHasBeenPoppedKey, @(YES), OBJC_ASSOCIATION_RETAIN);
return poppedViewController;
}
@end
4.3 UIViewController+MLFinder.m
#import "UIViewController+MLFinder.h"
#import "NSObject+MLFinder.h"
#import
const void *const kHasBeenPoppedKey = &kHasBeenPoppedKey;
@implementation UIViewController (MLFinder)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleSEL:@selector(viewDidDisappear:) withSEL:@selector(swizzled_viewDidDisappear:)];
[self swizzleSEL:@selector(viewWillAppear:) withSEL:@selector(swizzled_viewWillAppear:)];
//[self swizzleSEL:@selector(dismissViewControllerAnimated:completion:) withSEL:@selector(swizzled_dismissViewControllerAnimated:completion:)];
});
}
- (void)swizzled_viewDidDisappear:(BOOL)animated {
[self swizzled_viewDidDisappear:animated];
BOOL hasBeenPop = [objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue];
if (hasBeenPop) {
[self willDealloc];
}
}
- (void)swizzled_viewWillAppear:(BOOL)animated {
[self swizzled_viewWillAppear:animated];
BOOL hasBeenPop = [objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue];
//NSLog(@"----%d",hasBeenPop);
objc_setAssociatedObject(self, kHasBeenPoppedKey, @(NO), OBJC_ASSOCIATION_RETAIN);
}
@end
5:模拟代码
#import "TimerViewController.h"
@interface TimerViewController ()
@property (nonatomic, strong) NSTimer * timer;
@end
@implementation TimerViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"timer";
//dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//[self timerClick];
//});
//self.timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timerClick) userInfo:nil repeats:YES];
//[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
__weak typeof(self) ws = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:YES block:^(NSTimer * _Nonnull timer) {
[ws timerClick];
}];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- (void)timerClick {
NSLog(@"%s",__func__);
}
//- (void)viewWillDisappear:(BOOL)animated {
//if (self.timer != nil) {
//[_timer invalidate];
//_timer = nil;
//}
//}
-(void)dealloc {
NSLog(@"%s",__func__);
[_timer invalidate];
_timer = nil;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"---TimerViewController:viewWillAppear:%@",self);
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
NSLog(@"---TimerViewController:viewDidDisappear:%@",self);
}
@end
如果你觉得可以请添加我的公众号"洲洲哥"
推荐阅读
- 科学养胃,别被忽悠,其实真的很简单
- opencv|opencv C++模板匹配的简单实现
- django-前后端交互
- 松软可口易消化,无需烤箱超简单,新手麻麻也能轻松成功~
- 简单心理2019春A期+32+张荣
- 《算法》-图[有向图]
- IDEA|IDEA 创建工程
- android防止连续点击的简单实现(kotlin)
- 机器学习一些简单笔记
- Android超简单实现沉浸式状态栏