iOS 循环引用的问题总结
原因:
self -> Timer -> target(self), 造成循环引用
导致控制器不会销毁,不会调用dealloc 方法,内存泄漏
- (void)dealloc{
[_timer invalidate];
NSLog(@"********************delloc**************8");
}
解决方式:
1.API block的方式 iOS10以后可用
__weak typeof(self)weakself = self;
_timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
weakself.count++;
NSLog(@"-------%ld",weakself.count);
}];
2.手动破解循环
在适当的时机调用 (达到一定条件或者 例如在- (void)viewDidDisappear:(BOOL)animated {}调用,)
[self.timer invalidate];
self.timer = nil;
3. 借助runtime给对象添加消息处理的能力, 这种方式虽然能破解循环,但是 test 方法里获取到的self 是 _objct ,故感觉不太实用
// 借助runtime给对象添加消息处理的能力
_objct = [[NSObject alloc] init];
class_addMethod([_objct class], @selector(test), class_getMethodImplementation([self class], @selector(test)), "v@:");
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(test) userInfo:@"ddd" repeats:YES];
4.消息转发机制
创建一个中间类 PHJProxy,
@interface PHJProxy : NSObject
@property (nonatomic, weak) id target;
@end
@implementation PHJProxy //方法1:
//// 发送给target
//- (void)forwardInvocation:(NSInvocation *)invocation {
// [invocation invokeWithTarget:self.target];
//}
//// 给target注册一个方法签名
//- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
// return [self.target methodSignatureForSelector:sel];
//} // 方法2:
//仅仅添加了weak类型的属性还不够,为了保证中间件能够响应外部self的事件,需要通过消息转发机制,让实际的响应target还是外部self,这一步至关重要,主要涉及到runtime的消息机制。
-(id)forwardingTargetForSelector:(SEL)aSelector {
return self.target;
} @end
这2种方式原理都是一样,使用消息的转发机制,把消息转发到 target 中
补充:如果PHJProxy类 继承至NSProxy 时:
@interface LWProxy : NSProxy @property (nonatomic, weak) id target; + (instancetype)proxyWithTarget:(id)target; @end /**
NSProxy 类,是专门做消息转发的代理类,如果本类中没有方法实现,则不会去父类中查找,直接进入 -()methodSignatureForSelector{},进行转发
因此此类做消息转发比NSObject 效率更高
*/
@implementation LWProxy + (instancetype)proxyWithTarget:(id)target
{
// 只有alloc方法,没有init方法
LWProxy *proxy = [LWProxy alloc];
proxy.target = target;
return proxy;
} - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
} - (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation invokeWithTarget:self.target];
} @end
5. NSTimer 分类的方式,
@implementation NSTimer (LWTimer)
+ (NSTimer *)lw_timerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats
{
return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(timermethod:) userInfo:[block copy] repeats:YES];
} + (void)timermethod:(NSTimer *)timer
{
void (^block)() = timer.userInfo;
if (block) {
block();
}
}
@end
上述创建方式调用者是NSTImer自己,只是NSTimer捕获了参数block。这样我们在使用timer时,由于target的改变,就不再有循环引用了。
使用方式:
__weak typeof(self)weakself = self;
_timer = [NSTimer lw_timerWithTimeInterval:2 block:^{
weakself.count++;
NSLog(@"-------%ld",weakself.count);
} repeats:YES];
iOS10中,定时器的API新增了block方法,实现原理与此类似,这里采用分类为NSTimer添加了带有block参数的方法,而系统是在原始类中直接添加方法,最终的行为是一致的。
注意:
1、把timer改成弱引用
@property (nonatomic, weak) NSTimer *timer;
2. 使用__weak 那换个思路能不能让NSTimer弱引用target
__weak typeof(self) weakSelf = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakSelf selector:@selector(showMsg) userInfo:nil repeats:YES];
iOS 循环引用的问题总结的更多相关文章
- iOS循环引用
iOS循环引用 当前类的闭包/Block属性,用到了当前类,就会造成循环引用 此闭包/Block应该是当前类的属性,我们经常对Block进行copy,copy到堆中,以便后用. 单方向引用是不会产生循 ...
- iOS 循环引用解决方案
一.BLOCK 循环引用 一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身.构成循环引用. // 定义 block 的时候,会对外部变量做一次 cop ...
- iOS 循环引用
1.循环引用一般是指:A持有B,B同时持有A,从而导致死循环无法释放对象. 2.一般循环引用出现在block和delegate中,而一般解决方法就是将self变成weakSelf(强引用变成弱引用), ...
- iOS循环引用问题
今天面试问道了循环引用,所以就看了看,原来只是知道使用了Block容易造成循环引用.今天就来简单的介绍一些循环引用. 先来简单介绍一下什么是循环引用? 循环引用可以简单的理解成:A对象引用了B对象,B ...
- iOS 循环引用讲解(中)
谈到循环引用,可能是delegate为啥非得用weak修饰,可能是block为啥要被特殊对待,你也可能仅仅想到了一个weakSelf,因为它能解决99%的关于循环引用的事情.下面我以个人的理解谈谈循环 ...
- iOS循环引用常见场景和解决办法
好多场景会导致循环引用,例如使用Block.线程.委托.通知.观察者都可能会导致循环引用. 1.委托 遵守一个规则,委托方持有代理方的强引用,代理方持有委托方的弱引用. 实际场景中,委托方会是一个控制 ...
- iOS 循环引用 委托 (实例说明)
如何避免循环引用造成的内存泄漏呢: 以delegate模式为例(viewcontroller和view之间就是代理模式,viewcontroller有view的使用权,viewcontroller同时 ...
- iOS之weak和strong、懒加载及循环引用
一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...
- 【转】iOS学习之容易造成循环引用的三种场景
ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...
- 【原】iOS容易造成循环引用的三种场景,就在你我身边!
ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...
随机推荐
- 狠狠地切割(Hard Version)
狠狠地切割(Hard Version) (https://www.luogu.com.cn/problem/P8889) 跟easy版非常像,但是数据太大开标记数组的话会爆所.以得转换一下 开一个ma ...
- 音视频通讯QoS技术及其演进
利用多种算法和策略进行网络传输控制,最大限度满足弱网场景下的音视频用户体验. 良逸|技术作者 01 什么是QoS?音视频通讯QoS是哪一类? QoS(Quality of Service)是服务质量的 ...
- mybatis xml 中 大于、小于、等于 写法
在 *.xml 中使用常规的 < > = <= >= 会与xml的语法存在冲突 方法一:使用xml 原生转义的方式进行转义 字符名称 sql符号 转义字符 大于号 > & ...
- vite不能选配方案?vite-creater强势来袭!
我正在参加「掘金·启航计划」 项目背景 vite出现之后,迅速带走了一大波webpack的使用者,即使是对打包工具不熟悉的小白,也能很快感受到两者的区别--vite快的多! vite官方文档第一句也是 ...
- Java Lambda Stream
::方法使用 条件:lambada表达式的主体仅包含一个表达式,且lambada表达式只调用一个已经存在的方法:被引用的方法的参数列表与lambada表达式的输入输出一致 以下是Java 8中方法引用 ...
- BUG解决-Vscode/Sublime C++ 打印中文乱码问题
#include <iostream> using namespace std; #ifdef _WIN32 #include <windows.h> #endif int m ...
- cat,more,cp,mv,rm,命令
cat命令 查看文件内容 语法:cat[linux路径] more命令查看文件内容 more命令同样可以查看文件内容, 同cat不同的是: •cat是直接将内容全部显示出来 •more支持翻页,如果文 ...
- 2022-09-19:给定字符串 S and T,找出 S 中最短的(连续)子串 W ,使得 T 是 W 的 子序列 。 如果 S 中没有窗口可以包含 T 中的所有字符,返回空字符串 ““。 如果有不
2022-09-19:给定字符串 S and T,找出 S 中最短的(连续)子串 W ,使得 T 是 W 的 子序列 . 如果 S 中没有窗口可以包含 T 中的所有字符,返回空字符串 "&q ...
- VB.NET 截取字符串
在VB.NET中,您可以使用Substring方法或Split方法来截取字符串. Substring方法允许您从字符串中提取一个子字符串,该子字符串从指定的起始索引开始,并继续到字符串的末尾或指定的长 ...
- SQL Server修改列的数据类型
ALTER TABLE LJPA001H DROP CONSTRAINT DF_LJPA001H_pa_sex_1 ALTER TABLE LJPA001H ALTER COLUMN pa_sex V ...