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设备的内存.这些资源例如大量的数据,图片,音频,过多的控件等. 二.懒加 ...
随机推荐
- Android总结之json解析(FastJson Gson 对比)
前言: 最近为了统一项目中使用的框架,发现项目中用到了两种json解析框架,他们就是当今非常主流的json解析框架:google的Gson 和阿里巴巴的FastJson,为了废除其中一个所以来个性能和 ...
- 应用程序框架实战三十四:数据传输对象(DTO)介绍及各类型实体比较
本文将介绍DDD分层架构中广泛使用的数据传输对象Dto,并且与领域实体Entity,查询实体QueryObject,视图实体ViewModel等几种实体进行比较. 领域实体为何不能一统江湖? 当你阅读 ...
- Rust初步(七):格式化
在Rust中,如果要进行屏幕输出,或者写入到文件中,需要对数据进行格式化.这一篇总结一下它所支持的几种格式化方式. 这篇文章参考了以下官方文档,不过,按照我的风格,我还是会突出于C#语言的比较,这样可 ...
- java多线程--定时器Timer的使用
定时的功能我们在手机上见得比较多,比如定时清理垃圾,闹钟,等等.定时功能在java中主要使用的就是Timer对象,他在内部使用的就是多线程的技术. Time类主要负责完成定时计划任务的功能,就是在指定 ...
- Kooboo CMS 之TextContent详解
TextCotent 在Kooboo.CMS.Content下面,在View中有使用到这个模型层. TextContent继承了ContentBase,而ContentBase是由2个部分类组成的,一 ...
- 30行代码让你理解angular依赖注入:angular 依赖注入原理
依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖 ...
- 【WCF】WCF中的InstanceContext与ConcurrencyMode【转】
一.前言 最近忙于公司的在线升级项目,一个人要负责公司四大产品的在线升级,这四个产品是在Revit中以插件形式存在的,目前基于WCF来实现.等客户总量突破5万了,再重新用socket实现. 由于有服务 ...
- 让服务器iis支持.apk文件下载的设置方法
随着智能手机的普及,越来越多的人使用手机上网,很多网站也应手机上网的需要推出了网站客户端,.apk文件就是安卓(Android)的应用程序后缀名,默认情况下,使用IIS作为Web服务器的无法下载此文件 ...
- js 与JQuery显示及隐藏方法
虽然以后两种方式都能让文本信息隐藏和显示 第一种文本隐藏以后还是会占居位置, 第二种则不会占位置. <p id="p1">这是一段文本.</p> <i ...
- Java开发程序,使用编辑器编写创建Java项目、类
打开Eclipse 出现界面 工作空间的路径可以选择一个大空间的磁盘存放,点击确定: 创建:程序左上角-文件-新建-JAVA项目 输入项目名(项目名不能为中文),点击完成: 在 包资源管理器中点击 ...