常見原因:
一、 當(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)心self在block內(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
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í)慣很重要??
