iOS 處理循環(huán)引用的相關(guān)問題

常見原因:

一、 當(dāng)前VC使用了NSTimer, 并沒有對(duì)它進(jìn)行銷毀.
1:在計(jì)時(shí)結(jié)束或者離開頁面的時(shí)候,銷毀`timer`,步驟如下:
if(_timer) {
    [_timer invalidate];
    _timer = nil;
}
2.使用中間類,創(chuàng)建一個(gè)繼承NSObject的子類MyTimerTarget,添加一個(gè)weak屬性的對(duì)象,并創(chuàng)建開啟計(jì)時(shí)器的方法。
3.使用類方法,我們還可以對(duì)NSTimer做一個(gè)category,通過block將 timer的target和selector綁定到一個(gè)類方法上,來實(shí)現(xiàn)解除循環(huán)引用;
4.使用weakProxy,創(chuàng)建一個(gè)繼承NSProxy的子類MyProxy,并實(shí)現(xiàn)消息轉(zhuǎn)發(fā)的相關(guān)方法。
二、 block塊內(nèi)使用了self,造成了循環(huán)引用.

Tips1:一般的系統(tǒng)方法或者類方法不會(huì)造成循環(huán)引用,并不是所有的 block都會(huì)造成循環(huán)引用,一般只有實(shí)例方法的block塊內(nèi),調(diào)用了self的方法才會(huì)造成循環(huán)引用

Tips2:調(diào)用了performSelector延遲方法的,dealloc方法會(huì)延遲執(zhí)行
利用如下函數(shù)可以解決:
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil];

Tips3: 常見自定義cell里面的block循環(huán)引用

20230331172004.jpg

解決方案:1.使用__weak typeof(self) weakSelf = self;打斷循環(huán)引用
2.如果擔(dān)心selfblock內(nèi)提前釋放,可用如下解決方式

    @weakify(self);
    cell.didTag = ^(NSInteger tag) {
        @strongify(self);
        [self didJianGuanTag:tag];
    };
三、使用delegate, 用了strong修飾,要使用weak來修飾.

@property(nonatomic, weak) id<WEBidListTableViewCellDelegate>delegate;

四、NSNotificationCenter 使用 block注冊(cè)addObserver(forName:object:queue:using:),但是沒有在dealloc中移除;

如果在block內(nèi)使用了self,就要打破循環(huán)引用,搭配@weakify(self); @strongify(self);去解決:

@weakify(self);
 [[NSNotificationCenter defaultCenter]addObserverForName:@"RefreshMySelectImg" object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) {
     @strongify(self);
     [self.tableView reloadData];
 }];
五、vc中使用了WKWebView調(diào)用addScriptMessageHandler造成了循環(huán)引用.

前言結(jié)論:在與H5進(jìn)行交互時(shí),經(jīng)常使用 addScriptMessageHandler 添加參數(shù)信息,它需要添加一個(gè)
userContentController代理對(duì)象;
self 強(qiáng)引用- > WKWebView - > configuration參數(shù) ->userContentController

  1. userContentController強(qiáng)引用 - > self
解決方案1.在viewWillAppear 方法中添加 addScriptMessageHandler,在viewWillDisappear方法中移除調(diào)用
解決方案2. 打斷循環(huán)引用,具體如下調(diào)用使用
- (void)addJSHandler {
    id webViewSelf = [[WeakScriptMessageDelegate alloc] initWithDelegate:self];
    [self.webView.configuration.userContentController addScriptMessageHandler:webViewSelf name:@"js_close"];
}
// WeakScriptMessageDelegate.h
#import <Foundation/Foundation.h>

@interface WeakScriptMessageDelegate : NSObject <WKScriptMessageHandler>

@property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
@end
// WeakScriptMessageDelegate.m
#import "WeakScriptMessageDelegate.h"

@implementation WeakScriptMessageDelegate

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
@end

寫在后面:

  • iOS9 以后,使用 addObserver(selector:name:object:),或者addObserver(forKeyPath:options:context:) ,都不再需要手動(dòng)移除觀察者,系統(tǒng)會(huì)自動(dòng)在dealloc 的時(shí)候調(diào)用 [[NSNotificationCenter defaultCenter]removeObserver:self]。iOS9 以前的需要手動(dòng)進(jìn)行移除。所以為了適配,還是手動(dòng)添加上移除代碼為佳;
  • 觀察一個(gè)不會(huì)銷毀的對(duì)象(例如單例對(duì)象),不移除觀察者,會(huì)發(fā)生不確定的崩潰。所以還是手動(dòng)添加上移除監(jiān)聽的代碼為佳;

??:保持良好的代碼習(xí)慣很重要??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容