这次的例子是
1. 基于 iphone 项目.
2. 在模拟器上面测试的.
3. 基于 ARC.
例子比较简单, A ViewController 启动 B ViewController.
[self performSelector:@selector(block1) withObject:nil afterDelay:3.0f];
调用了 block1.
启动, 并点击 close 按钮, 关闭 B ViewController, 查看打印结果
3s 后打印如下
其实, 我想要的结果是, close 之后立即调用 dealloc, 但是现在需要 3s 后才调用.
试想一下, 如果来回切换并且达到一定次数, 是不是会内存泄露?!
不能忍!
大家可能会想, 是不是因为在 block1里面使用了 self, 造成无法立即释放.
那我们, 调用 block2
[self performSelector:@selector(block2:) withObject:nil afterDelay:3.0f];
看一下结果, 还是3s 后执行
block2 与 block1不同的就是, 使用了 weak 引用了当前 self(BViewcontroller).
这次, 至少告诉我们, self 已经是 null 了.
在调用一次 block3, 看看有没有新的发现.
[self performSelector:@selector(block3) withObject:nil afterDelay:3.0f];
还是3s 后得到结果
好吧, 醉了!
到底罪魁祸首是谁?
答案就是:
performSelector......
在调用
[self performSelector:@selector(block3) withObject:nil afterDelay:3.0f];
我才是对当前对象BViewcontroller有了 stong 的引用, 在 MRC 里面大家可以理解为 retain.
造成, 在 close 时, 无法立即释放自己(dealloc方法没有立即调用).
其实, apple 为我们提供了取消 performSelector 的方法.
再次运行, 可以发现, dealloc 方法立即调用了.
1. 基于 iphone 项目.
2. 在模拟器上面测试的.
3. 基于 ARC.
例子比较简单, A ViewController 启动 B ViewController.
主要代码在 B ViewController 里面.
@interface BViewController ()
@property (strong, nonatomic) NSMutableArray *tmpData;
@end
@implementation BViewController
- (void)dealloc
{
NSLog(@"---------------------------");
NSLog(@"MyViewController dealloc.");
NSLog(@"---------------------------");
}
- (void)viewDidLoad
{
[super viewDidLoad];
_tmpData = [NSMutableArray arrayWithObjects:@"mark.z", nil];
UIButton *cloneMeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[cloneMeBtn setTitle:@"close" forState:UIControlStateNormal];
cloneMeBtn.backgroundColor = [UIColor blueColor];
cloneMeBtn.frame = CGRectMake(130, 300, 80, 50);
[self.view addSubview:cloneMeBtn];
[cloneMeBtn addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside];
[self performSelector:@selector(block1) withObject:nil afterDelay:3.0f];
}
- (void)block1
{
[UIView animateWithDuration:1 animations:^{
NSLog(@"tmpArray = %@", self.tmpData);
[self.tmpData addObject:@"hk"];
NSMutableArray *array = self.tmpData;
[array addObject:@"ju"];
} completion:^(BOOL finished) {
}];
}
- (void)block2:(id)sender
{
NSLog(@"sender = %@", sender);
MyViewController __weak *weakSelf = sender;
[UIView animateWithDuration:1 animations:^{
NSLog(@"tmpArray = %@", weakSelf.tmpData);
[weakSelf.tmpData addObject:@"hk"];
NSMutableArray *array = weakSelf.tmpData;
[array addObject:@"ju"];
} completion:^(BOOL finished) {
}];
}
- (void)block3
{
[UIView animateWithDuration:1 animations:^{
NSLog(@"tmpArray = %@", _tmpData);
[_tmpData addObject:@"hk"];
NSMutableArray *array = _tmpData;
[array addObject:@"ju"];
NSLog(@"tmpArray = %@", _tmpData);
} completion:^(BOOL finished) {
}];
}
- (void)close
{
[self dismissViewControllerAnimated:YES completion:^{
}];
}
@end
[self performSelector:@selector(block1) withObject:nil afterDelay:3.0f];
调用了 block1.
启动, 并点击 close 按钮, 关闭 B ViewController, 查看打印结果
3s 后打印如下
tmpArray = (
"mark.z"
)
---------------------------
MyViewController dealloc.
---------------------------
其实, 我想要的结果是, close 之后立即调用 dealloc, 但是现在需要 3s 后才调用.
试想一下, 如果来回切换并且达到一定次数, 是不是会内存泄露?!
不能忍!
大家可能会想, 是不是因为在 block1里面使用了 self, 造成无法立即释放.
那我们, 调用 block2
[self performSelector:@selector(block2:) withObject:nil afterDelay:3.0f];
看一下结果, 还是3s 后执行
sender = (null)
tmpArray = (null)
---------------------------
MyViewController dealloc.
---------------------------
看来不是, self 的问题.block2 与 block1不同的就是, 使用了 weak 引用了当前 self(BViewcontroller).
这次, 至少告诉我们, self 已经是 null 了.
在调用一次 block3, 看看有没有新的发现.
[self performSelector:@selector(block3) withObject:nil afterDelay:3.0f];
还是3s 后得到结果
tmpArray = (
"mark.z"
)
tmpArray = (
"mark.z",
hk,
ju
)
---------------------------
MyViewController dealloc.
---------------------------
好吧, 醉了!
到底罪魁祸首是谁?
答案就是:
performSelector......
在调用
[self performSelector:@selector(block3) withObject:nil afterDelay:3.0f];
我才是对当前对象BViewcontroller有了 stong 的引用, 在 MRC 里面大家可以理解为 retain.
造成, 在 close 时, 无法立即释放自己(dealloc方法没有立即调用).
其实, apple 为我们提供了取消 performSelector 的方法.
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(nullable id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
- (void)close
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self dismissViewControllerAnimated:YES completion:^{
}];
}
再次运行, 可以发现, dealloc 方法立即调用了.