iOS之weak和strong、懒加载及循环引用

一、weak和strong

  1.理解

  刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成引用计数加1;而strong则相当于OC中规定retain,它会造成引用计数加1”。

  ARC的原理:只要还有一个变量指向对象,对象就会保持在内存中。当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放。这条规则对于实例变量、synthesize属性、局部变量都是适用的

  strong指针能够保持对象的生命,一个对象只要有strong指针指向它,那么它就不会被释放;相反的,如果一个没有一个strong指针指向它,那么它将会被自动释放。默认所有实例变量和局部变量都是Stong指针

  weak型的指针变量仍然可以指向一个对象,但不属于对象的拥有者。即当对象被销毁的时候,这个weak指针也就自动指向nil(空指针)。

  MARK传送门:MJ对于weak和strong的解析

  2.weak和strong指针使用注意

// 我们经常看到从xib中引用到控制器的属性都是weak型指针,为什么那些控件对象不会被自动释放?@property(nonatomic,weak) IBOOutlet UIButton *btn;// 原来在xib中创建或放置控件的时候,已经形成了这种引用关系 UIViewController->UIView->subView->UIButton// 进入到UIViewcontroller.h文件中,发现@property(null_resettable, nonatomic,strong) UIView *view;  // 这货是强引用的// 所以,上述的引用关系就是xib对这个button是强引用,你声明的属性对其是弱引用 

@interface LZVC ()@property (nonatomic,weak)UIView *myView;
@end

@implementation LZVC

- (void)viewDidLoad {
    [super viewDidLoad];
  //出现警告:("Warning: Assigning retained object to weak variable; object will be released after assignment")
  _myView = [[UIView alloc] initWithFrame:self.view.frame];  _myView.backgroundColor = [UIColor redColor];  [self.view addSubview:_myView];
}
@end

// 我们会发现_myView根本就没有被添加到self.view上面,因为_myView是一个weak型指针,没有持有对象的能力,在其等号后面初始化的那个成员变量在刚刚被初始化之后便由于没有强指针引用它便被自动释放了,所以_myView得到的为空。

// 更正方法:

// ①将成员属性声明中的weak改为strong。(直接让_myView强引用初始化的对象,如此初始化的对象就不会被自动释放了)

// ②将出现警告的地方改为如下所示:
// 由于所有的实例变量和局部变量默认都是strong型指针,所以myView强引用初始化的对象,而后_myView弱引用myViewUIView *myView = [[UIView alloc] initWithFrame:self.view.frame];
UIView *myView.backgroundColor = [UIColor redColor];
_myView = myView;
[self.view addSubview:_myView];  

  3.weak和strong的使用时机(根据上面的特征,我做出如下测试)

  1> 我新建了一个继承自UIView的子类TestView,新增了一个属性text,重写了它的dealloc方法,我想看看TestView什么时候释放

@property (nonatomic,copy)NSString *text;  // 属性
// 重写Dealloc并打印数据
-(void)dealloc
{
    NSLog(@"%@----%s",self.text,__func__);

  [super dealloc];
}

  2> 在控制器中,我写了如下代码

#import "LZVC.h"
#import "TestView.h"

@interface LZVC ()

@property (nonatomic,weak)TestView *myWeakView;  //弱引用

@property (nonatomic,strong)TestView *myStongView;  //强引用

@end

@implementation LZVC

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor  = [UIColor whiteColor];

    TestView *myWeakView = [[TestView alloc] initWithFrame:CGRectMake(0, 64, 160, 160)];
    myWeakView.backgroundColor = [UIColor redColor];
    myWeakView.text = @"我是弱引用的";
    _myWeakView = myWeakView;
    [self.view addSubview:_myWeakView];

    TestView *myStrongView = [[TestView alloc] initWithFrame:CGRectMake(160, 64, 160, 160)];
    myStrongView.backgroundColor = [UIColor greenColor];
    myStrongView.text = @"我是强引用的";
    _myStongView = myStrongView;
    [self.view addSubview:_myStongView];

}

#pragma mark点击屏幕触发
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (self.myWeakView) {
        [self.myWeakView removeFromSuperview];
    }
    if (self.myStongView) {
        [self.myStongView removeFromSuperview];
    }
}

  3> 点击屏幕后,两个view都从屏幕上被移除了,有如下打印,我们发现,弱引用的TestView被释放了(通过addSubviews,myWeakView有控制器对其强引用)

  4> 我返回主页,让这个LZVC控制器被销毁,又有打印,强引用的TestView(myStrongView除了控制器对其强引用外,声明的属性也对其强引用)

  5> 总结:相信从3、4的打印中都明白了,如果你想让一个控件的生命周期随着你的控制器被销毁才去释放,那就使用strong;如果你仅仅是想让它在被移除之后就被销毁,那就使用weak

二、懒加载

  1.懒加载

  懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小)。所谓懒加载,其实就是重写getter方法。说的通俗一点,就是在开发中,当程序中需要利用的资源时。在程序启动的时候不加载资源,只有在运行当需要一些资源时,再去加载这些资源。

  我们知道iOS设备的内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么就有可能会耗尽iOS设备的内存。这些资源例如大量数据,图片,音频等等,所以我们在使用懒加载的时候一定要注意先判断是否已经有了,如果没有那么再去进行实例化。

  2.使用懒加载的好处

  1> 不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强

  2> 每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合。且其中还进行了非空判断,防止对象被重复加载

  3> 只有当真正需要资源时,再去加载,节省了内存资源,防止对象被提前创建,也防止了使用对象时对象还没被创建的问题(内存优化,如加载plist文件等耗内存的操作)。

  3.使用懒加载初始化成员变量

@interface LZVC ()

@property (nonatomic,strong)NSArray *dataSource;

@end

@implementation LZVC

#pragma mark 懒加载
-(NSArray *)dataSource
{
    if (_dataSource == nil) {
        _dataSource = @[@"1",@"2",@"3",@"4"];
    }
    return _dataSource;
}

// 最后在用的时候采用self.dataSource形式方式即可

这里顺便说一说成员变量和属性的问题:

1> 直接访问成员变量:_dataSource = @[@"5",@"6"];  直接赋值,直观,快捷。

2> 访问成员属性:self.dataSource = @[@"5",@"6"];  当进行赋值的时候会走setter方法,当获取值的时候会走getter方法,我们可以在这两个方法里面做点自己想做的事情(例:在setter方法里面控制下数据有效性、监听值的改变等;而getter方法里面懒加载就可以体现出其好处了。

三、循环引用问题(场景)

  1.经典:代理模式Delegate(UITableViewDelegate)举例

  控制器的view强引用Tableview,而tableview的delegate又是控制器,如果下面两个代理属性用strong去修饰,就会造成循环引用问题,解决这个问题的最好办法就是两者其中之一对其弱引用就可以了(weak)。

@property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
@property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;

  2.NSTimer定时器Target造成循环引用,NSTimer会持有target对象。

  3.block作为成员变量,而在block中又访问了self或其属性造成循环引用

时间: 2024-10-25 14:40:14

iOS之weak和strong、懒加载及循环引用的相关文章

【IOS学习基础】weak和strong、懒加载、循环引用

一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成引用计数加1:而strong则相当于OC中规定retain,它会造成引用计数加1”. ARC的原理:只要还有一个变量指向对象,对象就会保持在内存中.当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放.这条规则对于实例变量.synthesize属性.局部变量都是适用的 strong指针能够保

IOS开发之Bug--View是懒加载导致出误以为是UI加载的bug

虽然分类为bug,但也算的上是一个问题,一个很简单的问题.先来看看问题的重现,就写了简单的Demo验证效果: 问题:点击ViewController跳转到TwoViewController,发现会延迟一下才出现. 这个问题也是在我工作开发中偶然遇到的,一开始不知道是什么原因.后来发现只要将TwoViewController中的: 箭头指向的一行代码注释去掉,或者添加一行关于任何view的任何操作,比如设置title.设置背景颜色.添加一个view等等操作,就可以避免苹果原生上面我遇到的问题. 解

IOS数据懒加载

懒加载,又称为延迟加载.说的通俗一点,就是在开发中,当程序中需要利用的资源时.在程序启动的时候不加载资源,只有在运行当需要一些资源时,再去加载这些资源. 我们知道iOS设备的内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么就有可能会耗尽iOS设备的内存.这些资源例如大量数据,图片,音频等等 下面举个例子: 1> 定义控件属性,注意:属性必须是strong的,示例代码如下: @property (nonatomic, strong) NSArray *imageList; 2>

iOS开发UI篇—懒加载

iOS开发UI篇—懒加载 1.懒加载基本 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化 2.使用懒加载的好处: (1)不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 (2)每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 3.代码示例 1 // 2 // YYViewController.m 3

IOS 懒加载模式

iOS开发—懒加载 1.懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行alloc init 2.我们知道iOS设备的内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么就有可能会耗尽iOS设备的内存.这些资源例如大量数据,图片,音频等等 下面举个例子: 1> 定义控件属性,注意:属性必须是strong的,示例代码如下: @property (nonat

iOS 开发——实用技术Swift篇&amp;Swift 懒加载(lazy)

Swift 懒加载(lazy) 在程序设计中,我们经常会使用 * 懒加载 * ,顾名思义,就是用到的时候再开辟空间,比如iOS开发中的最常用控件UITableView,实现数据源方法的时候,通常我们都会这样写 Objective-C 1 //必须实现的数据源代理方法 2 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 3 { 4 return self.dataArr

iOS开发UI基础—懒加载

iOS开发UI基础-懒加载 1.懒加载基本 懒加载--也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化 2.使用懒加载的好处: (1)不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 (2)每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 3.代码示例 1 // 2 // YYViewController.m

iOS设计模式之懒加载

一.为什么要懒加载? 答: iPhone设备内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么久可能会耗尽iOS设备的内存.这些资源例如大量的数据,图片,音频,过多的控件等. 二.懒加载思想是什么? 答: 简单的将就是拖到最后一刻,万不得已了,才加载,才开始占用资源.所谓懒加载,写的就是其getter方法.在开发中,当程序中需要利用的资源时,在程序启动的时候不加载,只有在运行当需要这些资源的时候再去加载这些资源. 三: 懒加载的好处 答: 1.不必将创建对象的代码全部写在view

iOS中的懒加载

iOS开发中 我们经常使用懒加载 1.懒加载的好处,让控件和对象在最需要加载的时候加载.这样可以节省内存空间,因为我们移动的设备资源还是比较宝贵的.所谓懒加载 就是推迟他的getter方法的执行. 比如.一个view的子控件 ,只有当这个view被显示的时候才去加载.一个tableViewCell中,给他设置了图片,他的content View里面才包含imageView的图片,只有设置了textLabel的内容,才会加载这个textLabel. //collectionView的数据源--属性