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弱引用myView
UIView *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或其属性造成循环引用
iOS之weak和strong、懒加载及循环引用的更多相关文章
- 【IOS学习基础】weak和strong、懒加载、循环引用
一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...
- iOS开发UI篇-懒加载、重写setter方法赋值
一.懒加载 1.懒加载定义 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再 ...
- IOS开发之Bug--View是懒加载导致出误以为是UI加载的bug
虽然分类为bug,但也算的上是一个问题,一个很简单的问题.先来看看问题的重现,就写了简单的Demo验证效果: 问题:点击ViewController跳转到TwoViewController,发现会延迟 ...
- ios 懒加载详解
iOS开发之懒加载 在iOS开发中几乎经常用到懒加载技术,比如我们存放网络数据的数组,控制器的view,控件的自定义,复杂的运算逻辑等等情况下都会用到懒加载技术,那么什么是懒加载呢?? 他又有什么样的 ...
- iOS开发UI篇—懒加载
iOS开发UI篇—懒加载 1.懒加载基本 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了, ...
- [IOS 开发] 懒加载 (延迟加载) 的基本方式,好处,代码示例
懒加载的好处: 1> 不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 2> 每个属性的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 ...
- iOS开发——UI基础-懒加载,plist文件,字典转模型,自定义view
一.懒加载 只有使用到了商品数组才会创建数组 保证数组只会被创建一次 只要能够保证数组在使用时才创建, 并且只会创建一次, 那么我们就称之为懒加载 lazy - (void)viewDidLoad 控 ...
- iOS 开发——实用技术Swift篇&Swift 懒加载(lazy)
Swift 懒加载(lazy) 在程序设计中,我们经常会使用 * 懒加载 * ,顾名思义,就是用到的时候再开辟空间,比如iOS开发中的最常用控件UITableView,实现数据源方法的时候,通常我们都 ...
- iOS设计模式之懒加载
一.为什么要懒加载? 答: iPhone设备内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么久可能会耗尽iOS设备的内存.这些资源例如大量的数据,图片,音频,过多的控件等. 二.懒加 ...
随机推荐
- Boot from Volume - 每天5分钟玩转 OpenStack(61)
Volume 除了可以用作 instance 的数据盘,也可以作为启动盘(Bootable Volume),那么如何使 volume 成为 bootable 呢? 现在我们打开 instance 的 ...
- android给View设置上下左右边框
给View控件设置边框,可以动态设置上下左右.通过布局文件就能搞定 1.在drawable文件夹下新建一个shape_main_list_bg.xml文件 <layer-list xmlns:a ...
- hdu4833 Best Financing(DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4833 这道题目关键的思想是从后往前dp,dp[i]表示在第i处投资xi能获得的最大收益,其中xi表示从 ...
- 【记录】从客户端()中检测到有潜在危险的 Request.Path 值。
从客户端()中检测到有潜在危险的 Request.Path 值. 错误信息: Application_Error Url: www.cnblogs.com/%E5%BA%.... UserAgent: ...
- geotrellis使用(十一)实现空间数据库栅格化以及根据属性字段进行赋值
Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html 目录 前言 安装空间数据库 空间数据库栅格化 根据属性字段进行赋 ...
- Flume官方文档翻译——Flume 1.7.0 User Guide (unreleased version)(二)
Flume官方文档翻译--Flume 1.7.0 User Guide (unreleased version)(一) Logging raw data(记录原始数据) Logging the raw ...
- Oracle Tuning 基础概述01 - Oracle 常见等待事件
对Oracle数据库整体性能的优化,首先要关注的是在有性能问题时数据库排名前几位等待事件是哪些.Oracle等待事件众多,随着版本的升级,数量还在不断增加,可以通过v$event_name查到当前数据 ...
- hibernate笔记--实体类映射文件"*.hbm.xml"详解
实体类就是指普通的POJO,Hibernate并不知道那个实体类对应数据库的哪一张表,所以还需要配置一下,常用的方式就是*.hbm.xml文件[配置与@注解配置,这里介绍前者的详细属性: <?x ...
- ASP.NET实现微信功能(2)(服务号高级群发)
前面写了一篇文章,关于微信的:http://www.cnblogs.com/kmsfan/p/4047097.html 今天打算来写本系列的第二批文章,服务号后台群发. 在写本篇文章之前,我们先来看看 ...
- springmvc原理
今天面试碰到一个特别恶心的公司面试官.是一个金融公司,过去后告诉我2点上班,带我去见经理.经理找人面试,看起来没有hr,经理直接看简历招人.经理上来就问我是xxx大学的,我说是,然后等面试官.面试官来 ...