0
点赞
收藏
分享

微信扫一扫

iOS开发循环引用

南柯Taylor 2021-09-19 阅读 67
发布文本

一、循环引用的产生

1.说明

-- :表示弱引用。

-> :表示强引用。

循环引用可以简单理解为对象A引用了对象B,而对象B又引用了对象A:A -> B -> A,此时双方都同时保持对方的一个引用,导致任何时候双方的引用计数都不为0,双方始终无法释放就造成内存泄漏。

当然不只是两个对象之间相互引用会形成循环引用,多个对象之间相互引用最终形成环同样会形成循环引用。

例如:A->B->C->....->X->B。

2.危害

循环引用对 app 有潜在的危害,会使内存消耗过高,导致内存泄漏,性能变差和 app 闪退等。

二、容易造成循环引用的三个场景

block 、 delegate 、NSTimer

1、delegate

self.tableView.delegate = self;
如果 delegate使用strong修饰就会构成循环引用:self -> tableView -> delegate -> self。

所以在定义delegate属性时使用weak便能解决这一问题:self -> tableView -- delegate -> self。tableView和delegate之间不是强引用,所以构不成循环。

规避delegate循环引用的杀手锏也是简单到哭:定义delegate属性时请用assign(MRC)或者weak(ARC),千万别手贱玩一下retain或者strong。

2.block

(1)并不是所有block都会产生循环引用,block是否产生循环引用是需要我们去判断的,例如

//这样是不会产生循环引用,因为这个block不被self持有,是被UIView的类对象持有,这个block和self没有任何关系,所以可以任意使用self。
[UIView animateWithDuration:0.0 animations:^{
    [self viewDidLoad];
}];

(2)self -> reachabilityManager -> block -> self,才会产生循环引用,并且XCode给出了循环引用warning,例如

//self -> reachabilityManager -> block -> self 都是循环引用
    self.reachabilityManager.stateBlock = ^(int number){
        NSLog(@"%@",self. reachabilityManager);
    };
//或者(block内部没有显式地出现"self",只要你在block里用到了self所拥有的东西,一样会出现循环引用!)
    self.reachabilityManager.stateBlock = ^(int number){
        NSLog(@"%@",_ reachabilityManager);
    };

(3)解决block循环引用的方法是使用__weak修饰self,然后在block里使用被修饰后的weakSelf来代替self:

__weak __typeof(self) weakSelf = self;
[self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    NSLog(@"%@",weakSelf.reachabilityManager);
}];
//但是仅仅使用__weak修饰self存在一个缺陷:__weak可能会导致内存提前回收weakSelf,在未执行NSLog()时,weakSelf就已经被释放了,然后执行NSLog()时就打印(null)。

//所以为了解决这个缺陷,我们需要这样在block内部再用__strong去修饰weakSelf:

__weak __typeof(self) weakSelf = self;
[self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    __strong __typeof(weakSelf) strongSelf = weakSelf;
    NSLog(@"%@",strongSelf.reachabilityManager);
}];
3. NSTimer

1、合适的时机启动和销毁 NSTimer
解决 NSTimer 的循环引用,我们首先会想到的方法应该是在 OneViewController dealloc 之前就销毁 NSTimer,这样循环就被打破了。
最简单的方法就是在 viewWillAppear 中启动 NSTimer,然后在 viewWillDisappear 中销毁 NSTimer,成对出现,绝对没有问题。

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
     self.time = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(log) userInfo:nil repeats:YES];
}
 
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.time invalidate];
    self.time = nil;
}

2、Effective Objective-C ”中的52条方法

#import <Foundation/Foundation.h>

@interface NSTimer (YPQBlocksSupport)

+ (NSTimer *)ypq_scheduledTimeWithTimeInterval:(NSTimeInterval)interval
                                         block:(void(^)())block
                                       repeats:(BOOL)repeats;

@end


#import "NSTimer+YPQBlocksSupport.h"

@implementation NSTimer (YPQBlocksSupport)


+ (NSTimer *)ypq_scheduledTimeWithTimeInterval:(NSTimeInterval)interval
                                         block:(void(^)())block
                                       repeats:(BOOL)repeats
{
    return [self scheduledTimerWithTimeInterval:interval
                                         target:self
                                       selector:@selector(ypq_blockInvoke:) userInfo:[block copy]
                                        repeats:repeats];
}

- (void)ypq_blockInvoke:(NSTimer *)timer
{
    void (^block)() = timer.userInfo;
    if(block)
    {
        block();
    }
}

@end
__weak ViewController * weakSelf = self;
[NSTimer ypq_scheduledTimeWithTimeInterval:4.0f
                                     block:^{
                                         ViewController * strongSelf = weakSelf;
                                         [strongSelf afterThreeSecondBeginAction];
                                     }
                                   repeats:YES];

计时器保留其目标对象,反复执行任务导致的循环,确实要注意,另外在dealloc的时候,不要忘了调用计时器中的 invalidate方法。

https://www.jianshu.com/p/41eb11ab4988
https://blog.csdn.net/qq_36557133/article/details/91355258
https://blog.csdn.net/qq_36557133/article/details/87654407
https://www.jianshu.com/p/ddfd1b3c0298

举报

相关推荐

0 条评论