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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...