iOS之weak和strong、懶載入及迴圈引用

来源:http://www.cnblogs.com/Mr-ios/archive/2016/01/29/5169649.html
-Advertisement-
Play Games

一、weak和strong 1.理解 剛開始學UI的時候,對於weak和strong的描述看得最多的就是“由ARC引入,weak相當於OC中的assign,但是weak用於修飾對象,但是他們都不會造成引用計數加1;而strong則相當於OC中規定retain,它會造成引用計數加1”。 ARC的原理:


一、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或其屬性造成迴圈引用


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1任何對象都有__proto__屬性 屬性值Object2並不是所有對象都有prototype屬性。只有方法對象(構造函數)以及基本數據類型還有Array,有prototype屬性;並且所有方法(對象)的prototype屬性都是object 在網上有很多關於原型的講解。在這裡我用console.l
  • 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.
  • a.nodejs安裝 nodejs的安裝沒有什麼說的預設安裝即可。安裝包官網下載即可:nodejs官網 本人用的是window的安裝包node-v4.2.6-x64.msi 安裝完成後打開命令行查看使用node -v命令查看安裝node版本,有版本號展示說明安裝成功啦 需要創建一個文件夾作為node
  • 給人做H5頁面時候,在下麵添加了微信二維碼,在安卓機中通過微信打開並長按圖片後能正常識別出來, 但是在蘋果系統就怎麼按都沒用,二維碼不能識別。 一行行代碼排查,也看過很多資料感覺還是識別時候,計算圖片高度有偏差,這可能和解析CSS樣式有關,無法正確計算出圖片在屏幕中的高度而導致識別時候有問題。 調整
  • 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.
  • 介紹了幾種清除浮動的方法
  • HTML5定稿了,終於有一種編程語言開發的程式可以在Android和IOS兩種設備上運行了 本文轉載自: http://www.cnblogs.com/tuyile006/p/4103634.html(只作轉載, 不代表本站和博主同意文中觀點或證實文中信息) 2007 年 W3C (萬維網聯盟)立項
  • 一篇不錯的資源博文,轉載分享給大家: 1、Android團隊提供的示例項目 如果不是從學習Android SDK中提供的那些樣例代碼開始,可能沒有更好的方法來掌握在Android這個框架上開發。由Android的核心開發團隊提供了15個優秀的示例項目,包含了游戲、圖像處理、時間顯示、開始菜單快捷方式
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...