【IOS學習基礎】weak和strong、懶載入、迴圈引用

来源:http://www.cnblogs.com/silence-wzx/archive/2016/01/19/5140978.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__); }

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


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

-Advertisement-
Play Games
更多相關文章
  • 效果圖1 string.xmlDefault Progressbar:2 attrs.xml 3 activity_main....
  • 源碼測試示例:package com.example.popupwindown;import android.os.Bundle;import android.app.Activity;import android.view.Gravity;import android.view.Menu;impo...
  • 一,效果圖。二,工程圖。三,代碼。RootViewController.h#import @interface RootViewController : UIViewController{ UITableView *myTableView;}@endRootViewController.m#i...
  • 本文目錄 1. iOS巨集的經典用法 2. Apple的習慣3. \_\_attribute\_\_ iOS巨集的經典用法 1.常量巨集、表達式巨集 2.帶參數的巨集 3.函數巨集(是一個沒有返回值的代碼塊,通常當做一行語句使用) 4.內聯函數 (一般有返回值) 5.變參巨集 函數可變參數 關於巨集定義...
  • 控制器 :一個iOS的app很少只由一個控制器組成,除非這個app極其簡單當app中有多個控制器的時候,我們就需要對這些控制器進行管理有多個view時,可以用一個大的view去管理1個或者多個小view,控制器也是如此,用1個控制器去管理其他多個控制器比如,用一個控制器A去管理3個控制器B、C、D,...
  • Swift語法基礎入門三(函數, 閉包)函數:函數是用來完成特定任務的獨立的代碼塊。你給一個函數起一個合適的名字,用來標識函數做什麼,並且當函數需要執行的時候,這個名字會被用於“調用”函數格式:func 函數名稱(參數名:參數類型, 參數名:參數類型...) -> 函數返回值 { 函數實現部分 }沒...
  • UIApplication對象特點:特點1:UIApplication對象是應用程式的象徵,一個UIApplication對象就代表一個應用程式,而且是單例的。(用來封裝整個應用程式的一個對象, 比如當應用程式執行到某個時期要做什麼, 生命周期等。)獲取UIApplication對象:[UIAppl...
  • Swift開發體驗/*:創建對象* OC: alloc initWithXXX 方法* Swift: (xxx:)*//*:調用方法* OC: [UIColor redColor];* Swift UIColor.redColor()*//*:枚舉* OC: UIB...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...