【IOS學習基礎】weak和strong、懶載入、循環參考,iosweak

來源:互聯網
上載者:User

【IOS學習基礎】weak和strong、懶載入、循環參考,iosweak
一、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(null 指標)。

  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__);}

  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被釋放了(因為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或其屬性造成循環參考

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.