ios - NSTimer中target的self是强引用问题
当控制器ViewController跳转进入控制器OneViewController中的时候开启定时器,让定时器每隔一段时间打印一次,当OneViewController dismiss的时候,控制器并没有被销毁.然而定时器的timer invalidate 在dealloc中已经写了.
如果没有定时器,则OneViewController可以正常销毁.
原因在于下图:循环引用
控制器ViewController跳转进入OneViewController中开启定时器
#import "OneViewController.h"
@interface OneViewController ()
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation OneViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
/**
1.__weak typeof(self) weakSelf = self; 不能解决
*/
//开启定时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(testTimerDeallo) userInfo:nil repeats:YES];
}
/** 方法一直执行 */
-(void)testTimerDeallo{
NSLog(@"-----");
}
- 当开启定时器以后,testTimerDeallo方法一直执行,即使dismiss此控制器以后,也是一直在打印,而且dealloc方法不会执行.循环引用造成了内存泄露,控制器不会被释放.
/** 开启定时器以后控制器不能被销毁,此方法不会被调用 */
-(void)dealloc{
NSLog(@"xiaohui");
[self.timer invalidate];
}
@end
- 解决办法: 由于循环引用的起因是target,则可以包装一个target,让target是另一个对象,而不是ViewController即可.
- 1.创建一个集成NSObject的分类TimerWeakTarget,创建类方法---开启定时器的方法
#import <Foundation/Foundation.h>
@interface TimerWeakTarget : NSObject
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *timer;
@property (nonatomic, weak) id target;
/**
1.重写开启定时器方法,在内部对target进行替换,换成本类(TimerWeakTarget)的对象即可
2.不会造成循环引用了,原控制器OneViewController属性有timer对timer强应用,timer内部对self强引用,但是self在此方法内部被替换成了本类的对象(TimerWeakTarget *),而本类的对象不会对OneViewController强引用,则不会造成循环引用,也就不会造成内存泄露
*/
+ (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats;
@end
- TimerWeakTarget.m文件中
- 在下面我们封装的类的方法中,我们将开启定时器的方法 [NSTimer scheduledTimerWithTimeInterval:interval target:timer selector:@selector(fire:) userInfo:userInfo repeats:repeats];中的target换掉了,换成了 本类的对象,timer.在OneViewController中开启定时器的时候直接调用这个类方法,就不会造成循环引用.看图
#import "TimerWeakTarget.h"
@implementation TimerWeakTarget
+ (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats{
TimerWeakTarget * timer = [TimerWeakTarget new];
timer.target = aTarget;
timer.selector = aSelector;
//-------------------------------------------------------------此处的target已经被换掉了不是原来的VIewController而是TimerWeakTarget类的对象timer
timer.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:timer selector:@selector(fire:) userInfo:userInfo repeats:repeats];
return timer.timer;
}
-(void)fire:(NSTimer *)timer{
if (self.target) {
[self.target performSelector:self.selector withObject:timer.userInfo];
} else {
[self.timer invalidate];
}
}
@end
- 控制器dismiss以后可以正常被销毁.问题解决.
ios - NSTimer中target的self是强引用问题的更多相关文章
- JVM中强引用,弱引用,软引用和幽灵引用的代码
上代码: public class ReferenceTest { public static void main(String[] args) { //test1();//软引用 //test2() ...
- Java中的四种引用类型,强引用,软引用,弱引用,虚引用
对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用.因此,引用也是JVM进行内存管理的一个重要概念. Java中对象的引用一般有以下4种类型: 1强引用 2软引用 3弱引用 ...
- Java四大引用详解:强引用、软引用、弱引用、虚引用
面试官考察Java引用会问到强引用.弱引用.软引用.虚引用,具体有什么区别?本篇单独来详解 @mikechen Java引用 从JDK 1.2版本开始,对象的引用被划分为4种级别,从而使程序能更加灵活 ...
- IOS开发中NSRunloop跟NSTimer的问题
在Windows时代,大家肯定对SendMessage,PostMessage,GetMessage有所了解,这些都是windows中的消息处理函数,那对应在ios中是什么呢,其实就是NSRunloo ...
- ios NSTimer的强引用问题
在一个controller中,使用 NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest ...
- IOS开发中滑动页面时NSTimer停止的问题
我们在做倒计时的时候,发现当你手指按着屏幕不放,拖动tableView滑动的时候,写在cell上得倒计时停止倒计时,松开继续倒计时.研究发现就是拖动tableView滑动时,NSTimer停止了. 这 ...
- iOS开发中如何创建多个target
在开发iOS应用程序的过程中,经常需要根据不同的需求,切换到不同的项目配置,或者打不同的包(测试环境.开发环境.生产环境等等),如果每次都是手动配置,一则比较麻烦,二则容易配置错,那么有没有更好的方案 ...
- iOS开发中的零碎知识点笔记 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 1.关联 objc_setAssociatedObject关联是指把两个对象相互关联起来,使得其中的一个对象作为另外 ...
- iOS开发系列-定时器强引用问题
概述 iOS开发中常用的定时器NSTimer.CADisplayLink. NSTimer 和 CADisplayLink 基本使用 NSTimer的创建方法有两个scheduledTimerWith ...
随机推荐
- Guava学习笔记(2):Preconditions优雅的检验参数
转自:http://www.cnblogs.com/peida/p/Guava_Preconditions.html 在日常开发中,我们经常会对方法的输入参数做一些数据格式上的验证,以便保证方法能够按 ...
- 2015年ACM长春网络赛(准备做掉7道:已经更新到6道)
总结汇总:模板 int getmax_min(char s[]) {//字符串的最大表示法:返回最小数组下标 , j = , k = ; while(i < len && j & ...
- TTrayIcon用法
TTrayIcon用法 self.trycn1.Icon:=Application.Icon; Self.trycn1.Hint:=self.Caption; self.trycn1.Visible: ...
- 网友分享 调用dll的语音朗读 不能变速,不好
调用 speeker.dll 这个文件被本人 放在文件里面,若有人需要可以 联系我 需要 mfc100ud.dll msvcr100d.dll 注:可以用D7 自带的ActiveX 里面的控件 ...
- Scrum项目8.0
目标:我们开始做每个需要细致的界面,比方说登陆,注册,游戏界面,难度选择 内容:登陆界面:登陆名,登陆密码,登陆按钮,以及优美的底图. 注册页面:名称,密码,登陆按钮,以及优美的底图. 游戏界面:难度 ...
- 常见的HTTP Headers
协议就是交互双方协商好要遵守的规范,打个不恰当的比方,就好像交谈双方约定要使用的同一种语言.如果我讲英文,你讲中文,大家都相互听不懂,交流那就得嗝屁了. HTTP协议就是需要交互的客户端(通常是浏览器 ...
- 【noip 2016】 组合数问题(problem)
杨辉三角形求组合数问题 原题点这里 #include <iostream> #include <cmath> using namespace std; long long a[ ...
- Android 之 ListView的学习
ListView 是一个控件,一个在垂直滚动的列表中显示条目的一个控件,这些条目的内容来自于一个ListAdapter .EditText Button TextView ImageView Chec ...
- iostat命令学习
iostat命令主要用于监控linux系统下cup和磁盘IO的统计信息 可以通过iostat --help获得该命令的帮助信息 [oracle@std ~]$ iostat --help Usage: ...
- 为什么匿名内部类的参数必须为finalhttp://feiyeguohai.iteye.com/blog/1500108
1) 从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变量(形式参数或局部变量)是天经地义的.是很自 ...