iOS内存话题: performSelector 导致不立即 dealloc
2015-11-16 23:53
651 查看
这次的例子是
1. 基于 iphone 项目.
2. 在模拟器上面测试的.
3. 基于 ARC.
例子比较简单, A ViewController 启动 B 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 的方法.
修改 close 方法的代码
再次运行, 可以发现, 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;
修改 close 方法的代码
- (void)close { [NSObject cancelPreviousPerformRequestsWithTarget:self]; [self dismissViewControllerAnimated:YES completion:^{ }]; }
再次运行, 可以发现, dealloc 方法立即调用了.
相关文章推荐
- nagios_client_V1-sh
- iOS 屏幕适配
- iOS中消息的传递机制
- iOS中消息的传递机制
- iOS 调节屏幕明暗度
- iOS---APNS(自带)
- iOS开发之Tom猫
- iOS学习:调用相机,选择图片上传,带预览功能
- iOS - Umeng分享
- iOS 多图上传
- iOS - 消息推送
- iOS开发之图片查看器
- iOS - 数据持久化---- NSUserDefaults & NSKeyedArchiver
- iOS小技巧-第三方sdk官网汇总(逐步积累)
- iOS - 常用正则表达式
- iOS - NSDateFormatter 日期 和 字符串
- iOS深入学习Block
- iOS - __weak&&__block
- iOS 拨打电话的方法总结
- ios自动布局(1)