美文网首页
iOS内存管理学习记录

iOS内存管理学习记录

作者: 宋鸿康iOS | 来源:发表于2018-03-09 17:30 被阅读15次

ARCAutomatic Reference CountingARC工作方式是在代码编译的时候,自动加入内存控制代码,来控制对象的生命周期,确保对象使用的内存空间正确的分配和释放。在ARC中我们不能使用MRC的关键字,例如:release,retain,autorelease.

基本上ARC已经能解决项目中的90%的内存管理问题,但是有些循环引用还是需要我们程序员手动去释放,下面列举项目中经常出现的循环引用的问题。
1、block的循环引用

#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) NSString *testString;
@property (strong,nonatomic)void (^blockTest)(NSString *);
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.blockTest = ^(NSString *string) {
        self.testString = string;
    };
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

编译器会提示 Capturing 'self' strongly in this block is likely to lead to a retain cycle

根据提示,我们可以肯定的是,上面的代码出现了循环引用了。

此时block强引用self,self强引用block,这样就造成了循环引用。如何打破循环引用?只需要self变弱就就好了。

备注:只要在block使用了self中的属性或者方法,就是属于block强引用了self,为什么呢? 具体看下block实现原理,因为我也不知道哈哈哈😆


__weak typeof(self) weakSelf = self
self.blockTest = ^(NSString *string) {
    weakSelf.testString = string;
};
上面的解决方案能够满足我们开发的需求,但是还是有点问题,下面举个例子
classA push 到classB

@interface ClassB ()

@property (nonatomic, copy) dispatch_block_t block;
@property (nonatomic, strong) NSString *str;
@property (nonatomic, strong) ClassA *classA;

@end

@implementation ClassB

  • (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.classA = [[ClassA alloc] init];
    self.classA.delegate = self;

    self.str = @"111";
    __weak typeof(self) weakSelf = self;
    self.block = ^{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"%@",strongSelf.str);
    });
    };
    self.block();
    }

  • (void)dealloc
    {
    NSLog(@"dealloc");
    }

1、在5秒后 `pop`到`classA`,`nslog` 会打印 `null`,
2、在5秒内 `pop` 到`classA`,`nslog`会打印`1111`.
造成上面的原因很浅显了。。。。classB被dealloc,_str属性也会被release,所以就是null.
解决上面的问题

self.str = @"111";
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf.str);
});
};
self.block();

在blcok内部,声明一个变量`strongSelf` 放在栈区,`classB`的`retainCount+1`,当`block`执行完,`strongSelf`才会被回收。此时就能解决以上问题。

2、单利模式的循环引用
代码如下

@protocol ClassADelegate <NSObject>

  • (void)fuck;
    @end
    @interface ClassA : UIViewController
    @property (nonatomic, strong) id <ClassADelegate>delegate;
    @end

@interface ClassB ()

@property (nonatomic, strong) ClassA *classA;
@end
@implementation ClassB

  • (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.classA = [[ClassA alloc] init];
    self.classA.delegate = self;
    }
A强引用B,B又强引用A,造成了循环引用,。修改方法如下:
`@property (nonatomic,weak) id <ClassADelegate>delegate;`


总结循环引用,只需要打破这个圈即可。


相关文章

网友评论

      本文标题:iOS内存管理学习记录

      本文链接:https://www.haomeiwen.com/subject/qjpyfftx.html