CADisplayLink、NSTimer迴圈引用解決方案

来源:https://www.cnblogs.com/r360/archive/2022/07/08/16456965.html
-Advertisement-
Play Games

前言:CADisplayLink、NSTimer 迴圈引用問題 ​ CADisplayLink、NSTimer會對Target產生強引用,如果target又對他們產生強引用,那麼就會引發迴圈引用。 @interface ViewController () @property (nonatomic, ...


前言:CADisplayLink、NSTimer 迴圈引用問題

​ CADisplayLink、NSTimer會對Target產生強引用,如果target又對他們產生強引用,那麼就會引發迴圈引用。

@interface ViewController ()

@property (nonatomic, strong) CADisplayLink *link;
@property (nonatomic, strong) NSTimer *time;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 保證調用頻率和刷幀頻率 60fps
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];
    [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode] ;
    
    self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeTest) userInfo:nil repeats:YES]; 
}

- (void)timeTest {
    NSLog(@"%s", __func__);
}

- (void)linkTest {
    NSLog(@"%s", __func__);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"%s", __func__);
    [self.time invalidate];
}

__weak typeof(self) weakSelf = self;能否解決NSTimer的迴圈引用問題?

答:我們並不能夠通過__weak typeof(self) weakSelf = self;代碼來實現解決迴圈引用。

__weak typeof(self) weakSelf = self;是用在block內可以解決迴圈引用的問題。

​ NSTime 使用提供 block 的 API ,通過 __weak 解決循序引用問題

- (void)viewDidLoad {
    [super viewDidLoad];
    
    __weak typeof(self) weakSelf = self;
    self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf timeTest];
    } ];
}

- (void)timeTest {
    NSLog(@"%s", __func__);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"%s", __func__);
    [self.time invalidate];
}

方案二、使用 NSObject 消息轉發

​ 通過中間變數,是中間的一個引用變成弱引用。

​ 第一步:創建繼承 NSObject 的 RHMiddleTarget 中間文件,創建 target 屬性,使用 weak 弱引用修飾

#import <Foundation/Foundation.h>

@interface RHMiddleTarget : NSObject

@property (nonatomic, weak) id target;

+ (instancetype)middleTargetWithTarget:(id)target;

@end


#import "RHMiddleTarget.h"

@implementation RHMiddleTarget

+ (instancetype)middleTargetWithTarget:(id)target {
    RHMiddleTarget *middleTarget = [[RHMiddleTarget alloc] init];
    middleTarget.target = target;
    return middleTarget;
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    // 返回可以處理的對象, 給對象發送aSelector消息
    // objc_msgSend(self.target, aSelector);
    return self.target;
}

@end

第二步:在使用 CADisplayLink 和 NSTimer 中的 target 傳到中間變數里:

    // 保證調用頻率和刷幀頻率 60fps
    self.link = [CADisplayLink displayLinkWithTarget:[RHMiddleTarget middleTargetWithTarget:self] selector:@selector(linkTest)];
    [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode] ;
    
    self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[RHMiddleTarget middleTargetWithTarget:self] selector:@selector(timeTest) userInfo:nil repeats:YES];

第三步:測試驗證:

2022-07-05 16:01:47.895716+0800 Interview03-定時器[10828:260303] -[ViewController timeTest]
2022-07-05 16:01:48.895649+0800 Interview03-定時器[10828:260303] -[ViewController timeTest]
2022-07-05 16:01:49.895571+0800 Interview03-定時器[10828:260303] -[ViewController timeTest]
2022-07-05 16:01:50.666056+0800 Interview03-定時器[10828:260303] -[ViewController touchesBegan:withEvent:]

方案三、使用 NSProxy 消息轉發

第一步:創建繼承 NSObject 的 RHMiddleTarget 中間文件,創建 target 屬性,使用 weak 弱引用修飾

#import <Foundation/Foundation.h>

@interface RHMiddleTarget : NSProxy

@property (nonatomic, weak) id target;

+ (instancetype)middleTargetWithTarget:(id)target;

@end

#import "RHMiddleTarget.h"

@implementation RHMiddleTarget

+ (instancetype)middleTargetWithTarget:(id)target {
    RHMiddleTarget *middleTarget = [RHMiddleTarget alloc];
    middleTarget.target = target;
    return middleTarget;
}

// 返回方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

// 進行相應的調用
- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}

第二步:在使用 CADisplayLink 和 NSTimer 中的 target 傳到中間變數里

    // 保證調用頻率和刷幀頻率 60fps
    self.link = [CADisplayLink displayLinkWithTarget:[RHMiddleTarget middleTargetWithTarget:self] selector:@selector(linkTest)];
    [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode] ;
    
    self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[RHMiddleTarget middleTargetWithTarget:self] selector:@selector(timeTest) userInfo:nil repeats:YES];

第三步:測試驗證

2022-07-05 16:27:25.427454+0800 Interview03-定時器[11550:281823] -[ViewController linkTest]
2022-07-05 16:27:25.444101+0800 Interview03-定時器[11550:281823] -[ViewController linkTest]
2022-07-05 16:27:25.456983+0800 Interview03-定時器[11550:281823] -[ViewController touchesBegan:withEvent:]

方案四、使用 viewWillDisappear

​ 在控制器銷毀或者定時器停止的時候,調用如下的方法

 [self.timer invalidate];
 [self.link invalidate];
 self.timer = nil;
 self.link = nil;

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

-Advertisement-
Play Games
更多相關文章
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 前言 本文主要學習 ROS機器人操作系統 ,在ROS系統里調用 OpenCV庫 實現人臉識別任務 一、環境配置 1.安裝ROS sudo apt-get install ros-kinetic-desktop-full 2.攝像頭調用 安裝攝像頭 ...
  • 摘要 RadonDB MySQL Kubernetes v2.2.0 於近日發佈!該版本開始支持 MySQL 8.0,備份功能優化,並全面提升高可用穩定性。社區同步發起“新版試用贏周邊”活動! 致謝 感謝 @runkecheng、 @acekingke、 @andyli029 、@zhl003、 @ ...
  • 作為雲原生技術先驅,騰訊雲資料庫內核團隊致力於不斷提升產品的可用性、可靠性、性能和可擴展性,為用戶提供更加極致的體驗。為幫助用戶瞭解極致體驗背後的關鍵技術點,本期帶來騰訊雲資料庫專家工程師王魯俊給大家分享的騰訊雲原生資料庫TDSQL-C的架構探索和實踐,內容主要分為四個部分: 本次分享主要分為四個部 ...
  • Tapdata Live Data Platform 發佈會演講精華總結+直播回放!閱讀文章詳情,獲取首批體驗官專屬權益!時代為何需要一個全新的實時數據架構?Tapdata 技術架構有何優勢和特性?Tapdata 的開源路線圖又是怎樣? ...
  • 原文鏈接:三分鐘走進袋鼠雲一站式全自動化全生命周期運維管家ChengYing(承影) 課件獲取:關註公眾號 ** “數棧研習社”,後臺私信 “ChengYing”** 獲得直播課件 視頻回放:點擊這裡 ChengYing 開源項目地址:github 丨 gitee 喜歡我們的項目給我們點個** ST ...
  • 表的約束: 關鍵字:constraint 約束是一種表級別的限制,它通過對錶的數據限制來保證數據的完整性和一致性 常見約束: 主鍵約束(primary key) 用途:就是用來約束其中的一列,作為所有列中的標識符(這一列的唯一代表), 在一張表中通過主鍵可以準確定位到一列。可以避免列中數據的重覆。 ...
  • 近年來,各類欺詐案件屢見報端,“金融造富”的騙局防不勝防。網上銀行欺詐、電話銀行欺詐、網路欺詐、電信欺詐、盜刷銀行卡、POS機套現、貸款欺詐……龐大的利益誘惑下,金融詐騙黑產的水深不見底。各大銀行風控部門也一直在致力於迭代反欺詐系統守衛人民財產。 反詐困境 某國有大型銀行信用卡中心在與騰訊雲溝通時曾 ...
  • 互聯網時代下,網路直播帶貨流量數據爆發明顯,許多app的出海同時開拓了潛力巨大的海外網購市場,進行跨境電商直播既可以刺激商品消費,又可以把中國文化帶向世界。但目前跨境直播帶貨的問題在於語言問題,很多外國網友並不能聽懂中文主播所講的內容,要兼備外語與帶貨能力的主播又非常稀缺。 HMS Core機器學習 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...