【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(, , , )];
myWeakView.backgroundColor = [UIColor redColor];
myWeakView.text = @"我是弱引用的";
_myWeakView = myWeakView;
[self.view addSubview:_myWeakView]; TestView *myStrongView = [[TestView alloc] initWithFrame:CGRectMake(, , , )];
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 = @[@"",@"",@"",@""];
}
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.block作为成员变量,而在block中又访问了self或其属性造成循环引用
【IOS学习基础】weak和strong、懒加载、循环引用的更多相关文章
- Swift语法基础入门四(构造函数, 懒加载)
Swift语法基础入门四(构造函数, 懒加载) 存储属性 具备存储功能, 和OC中普通属性一样 // Swfit要求我们在创建对象时必须给所有的属性初始化 // 如果没办法保证在构造方法中初始化属性, ...
- Spring5.0源码学习系列之浅谈懒加载机制原理
前言介绍 附录:Spring源码学习专栏 在上一章的学习中,我们对Bean的创建有了一个粗略的了解,接着本文挑一个比较重要的知识点Bean的懒加载进行学习 1.什么是懒加载? 懒加载(Lazy-ini ...
- iOS 开发UI篇 -- 懒加载学习
1. 懒加载基本 懒加载--也称为延迟加载,即在需要的时候才加载( 效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实 ...
- iOS 开发——实用技术Swift篇&Swift 懒加载(lazy)
Swift 懒加载(lazy) 在程序设计中,我们经常会使用 * 懒加载 * ,顾名思义,就是用到的时候再开辟空间,比如iOS开发中的最常用控件UITableView,实现数据源方法的时候,通常我们都 ...
- 【转】ViewPager学习笔记(一)——懒加载
在项目中ViewPager和Fragment接口框架已经是处处可见,但是在使用中,我们肯定不希望用户在当前页面时就在前后页面的数据,加入数据量很大,而用户又不愿意左右滑动浏览,那么这时候ViewPag ...
- [转]ViewPager学习笔记(一)——懒加载
在项目中ViewPager和Fragment接口框架已经是处处可见,但是在使用中,我们肯定不希望用户在当前页面时就在前后页面的数据,加入数据量很大,而用户又不愿意左右滑动浏览,那么这时候ViewPag ...
- Vue-Router学习第二弹动态路由\懒加载\嵌套路由
在我们做项目时肯定会有出现动态路由: 举个栗子: 一个品种的商品页面会有同类不同样的商品就要在路由的后面加一个id: Vue的路由id是这样添加的: 两种动态路由 一种是params参数添加: 首先现 ...
- Swift 学习一函数&函数属性&懒加载
函数 函数相当于OC中的方法 格式: func 函数名(参数列表) -> 返回值类型 { 代码块 return 返回值} func 函数名(参数列表){ // 返回值为Void 可 ...
- js学习之原生js实现懒加载
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- swift学习第十六天:懒加载和tableView
懒加载 懒加载的介绍 swift中也有懒加载的方式 (苹果的设计思想:希望所有的对象在使用时才真正加载到内存中) 和OC不同的是swift有专门的关键字来实现懒加载 lazy关键字可以用于定义某一个属 ...
随机推荐
- 探究foreach对于迭代变量的封装性的研究
众所周知教科书上对于foreach之中的注释是在遍历过程中无法改变其遍历的元素例如声明一个数组 ,,,}; foreach(int m in ii){ m = ;//错误 “m”是一个“foreach ...
- Know Thy Complexities!
http://bigocheatsheet.com/ Hi there! This webpage covers the space and time Big-O complexities of c ...
- elasticsearch,http://ip:9200访问不到的解决办法
现在解压elasticsearch之后,启动,通过http://localhost:9200可以访问的到,但是http://ip:9200访问不到,怎么办呢?带你解决,带你飞 修改elasticsea ...
- weblogic开机启动脚本
1.在/home/bea/startBeaAll目录内创建一个startBeaAll.sh文件,加入如下内容(把相应目录与命令修改即可,红字部分为修改地方): #!/bin/sh echo " ...
- Gengxin讲STL系列——Set
本系列第二篇blog 第一篇写的心潮澎湃,结果写完一看,这都是些什么玩意= =| Set的中文名称是“集合”.集合,高一数学必修一课本给出的定义已经很明确了,简单来讲就是一个不含重复元素的空间(个人定 ...
- python多线程抓取网页信息
#!/usr/env python #-*- coding: utf-8 -*- import urllib import urllib2 import random import requ ...
- TRIGGERS_监测系统_原始数据表触发器—调用告警信息存储过程
//每次向originaldata表中插入数据就会触发该触发器 create or replace trigger originaldata_to_alarm after insert on ori ...
- Ubuntu Codeblocks Installation
Download and Installation sudo add-apt-repository ppa:damien-moore/codeblocks sudo apt update sudo a ...
- 搜索打表大找规律 (hdu2045)
不容易系列之(3)—— LELE的RPG难题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/O ...
- C++----练习--引用头文件
1.创建头文件和源文件 touch /tmp/tools.h touch /tmp/main.cpp 2.各文件的内容如下: tools.h #include<iostream> void ...