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或其屬性形成循環引用