1.理解测试
刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak至关于OC中的assign,可是weak用于修饰对象,可是他们都不会形成引用计数加1;而strong则至关于OC中规定retain,它会形成引用计数加1”。优化
ARC的原理:只要还有一个变量指向对象,对象就会保持在内存中。当指针指向新值,或者指针再也不存在时,相关联的对象就会自动释放。这条规则对于实例变量、synthesize属性、局部变量都是适用的atom
strong指针可以保持对象的生命,一个对象只要有strong指针指向它,那么它就不会被释放;相反的,若是一个没有一个strong指针指向它,那么它将会被自动释放。默认全部实例变量和局部变量都是Stong指针spa
weak型的指针变量仍然能够指向一个对象,但不属于对象的拥有者。即当对象被销毁的时候,这个weak指针也就自动指向nil(空指针)。.net
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的使用时机(根据上面的特征,我作出以下测试)code
1> 我新建了一个继承自UIView的子类TestView,新增了一个属性text,重写了它的dealloc方法,我想看看TestView何时释放对象
@property (nonatomic,copy)NSString *text; // 属性
// 重写Dealloc并打印数据 -(void)dealloc { NSLog(@"%@----%s",self.text,__func__);
[super dealloc]; }
2> 在控制器中,我写了以下代码blog
#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> 总结:相信从三、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.block做为成员变量,而在block中又访问了self或其属性形成循环引用