我们都知道只要发生循环引用,就在造成内存泄漏,但导致内存泄漏还有很多种情况,且听我述来
self持有block时,不能在block里使用self或者通过_property访问属性
例如
(ARC环境下)
self.block = ^{
[self doSomething]; //会造成循环引用
self.property; //会造成循环引用
_property; //会造成循环引用
};
因为都造成block持有self,因此需声明weakself,具体怎么做呢,就是__weak typeof(self) weakself = self;
这样声明后,在block中用weakself代替self,就不会让block持有self,并且能通过weakself访问到self的方法和属性,双赢。但要注意,引用属性时不能用下划线+属性名,必须weakself.property
,因此上面的代码可以换做
__weak typeof(self) weakself = self;
self.block = ^{
[weakself doSomething]; //不会造成循环引用
weakself.property; //不会造成循环引用
};
需要写成单例,否则会循环引用
但有个问题,同一时刻只能有一个网络请求。异步会有问题。当两个线程同时申请manager对象时,肯定有一个manager申请不到,无法网络请求
好了直接上图
解决的方法还是声明weakself
关于更多block的内容,请戳BLOCK 探索
新手往往会犯这种错误,push 到一个节面,返回之前的节面再继续push,这时候之前的界面不会调用delloc,不会被销毁掉,因为只有dismiss才会调用Controller的delloc。
如图,如果在view里声明代理时用了strong关键词,就会造成循环引用,因此我们一般使用weak关键字修饰delegate,就不会发生循环引用了。
具体就是
@property (nonatomic,weak) id delegate;
iOS内存管理中的ARC只会对OC对象在编译后加上retain、release和autoreleasepool,因此其他的对象就需要开发者手动管理内存了
譬如CoreFoundation对象(C对象) :
只要函数中包含了create\new\copy\retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease或者其他release函数、C语言代码中的malloc等需要对应free等都需要注意,否则就不会被释放,造成内存泄漏
当我们用到下面这个方法
(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)
aTarget一般传入self,然后便会持有self,当self需要释放时,因为被持有,因此不能释放,出现泄漏,需声明weakSelf;
@autoreleasepool {}中创建的临时对象在pool销毁时才会销毁生成的对象,因此在一个autoreleasepool里大量添加任务就会内存会飙升,可能会导致内存泄漏,如果有类似需求,则在每一个任务外面加上autoreleasepool,每一个pool结束之后都会销毁对象,内存趋于平稳
@autoreleasepool {
for(int i=1 ; i<100000; i++){
//task
}
}
替换成
@autoreleasepool {
for(int i=1 ; i<100000; i++){
@autoreleasepool {
//task
}
}
}
什么时候这么做呢
根据苹果官方文档中对 Using Autorelease Pool Blocks 的描述,我们知道在下面三种情况下是需要我们手动添加 autoreleasepool 的:
如果你编写的程序不是基于 UI 框架的,比如说命令行工具;
如果你编写的循环中创建了大量的临时对象;
如果你创建了一个辅助线程。
参考:https://www.jianshu.com/p/f5bc47607613
参考:https://blog.csdn.net/Mr_XiaoJie/article/details/52953807