如何破除循环引用
1.避免产生循环引用
2.在适合的时机手动断环
--weak(代理) --block(block方面) --unsafe_unretained(没有增加应用计数,但是对象被回收但是指针没有置为nil)
--block破解循环引用
在MRC下--block修饰对象不会增加引用计数,避免循环引用;
在ARC下--block修饰对象会被强引用,无法避免循环引用,需手动解环。
--unsafe_unretained 不会增加引用计数,避免循环引用;如果修饰对象在某时机被释放,会产生悬垂指针,导致内存泄露
举个例子NSTimer
总结:通过创建一个中间对象,然后中间对象持有两个弱饮用对象,NSTImer分派的任务(fire)实际是在中间对象中实现的,在fire方法进行判断如果对象target没有被释放那就只执行selector,如果被释放就执行invalidate方法来解除runloop对timer的持有。
代码如下:
@interface NSTimer (WTimer)
+ (NSTimer *)scheduledWeakTimerInterval:(NSTimeInterval)interval
target:(id)aTarget
selector:(SEL)aSelector
unserInfo:(id)userInfo
repeats:(BOOL)repeaters;
@end
//
// NSTimer+WTimer.m
// MM--NSTimer
//
// Created by maochengfang on 2020/11/8.
//
#import "NSTimer+WTimer.h"
@interface TimerWeakObject : NSObject
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *timer;
- (void)fire:(NSTimer *)timer;
@end
@implementation TimerWeakObject
- (void)fire:(NSTimer *)timer{
if(self.target){
if([self.target respondsToSelector:self.selector]){
[self.target performSelector:self.selector withObject:timer.userInfo];
}
}else{
[self.timer invalidate];
}
}
@end
@implementation NSTimer (WTimer)
+ (NSTimer *)scheduledWeakTimerInterval:(NSTimeInterval)interval
target:(id)aTarget
selector:(SEL)aSelector
unserInfo:(id)userInfo
repeats:(BOOL)repeaters{
TimerWeakObject* object = [[TimerWeakObject alloc] init];
object.target = aTarget;
object.selector = aSelector;
object.timer = [NSTimer scheduledWeakTimerInterval:interval target:object selector:@selector(fire:) unserInfo:userInfo repeats:repeaters];
return object.timer;
}
@end