循環(huán)引用也就是引用之后造成的一個循環(huán)用圖理解吧
下面是可能造成循環(huán)引用的幾種情況
1.協(xié)議代理
都知道協(xié)議的代理對象都用weak修飾,哪為何不用strong,或者copy呢掌测?答案是會造成循環(huán)引用。下面就用代碼解釋吧
#import <Foundation/Foundation.h>
//協(xié)議
@protocol TestToolDelegate <NSObject>
- (void)protacolTest:(NSString *)string;
@end
@interface TestTool : NSObject
//使用strong會造成循環(huán)引用
@property (nonatomic,strong)id <TestToolDelegate> delegate;
@end
上面是聲明的協(xié)議,下面是一個類對象瘫镇,類對象里強引用了delegate對象
下面來看下TestTool的使用
@interface ViewController ()<TestToolDelegate>
@property (nonatomic,strong)TestTool *tool;
@end
@implementation ViewController1
- (void)viewDidLoad {
[super viewDidLoad];
self.tool = [[TestTool alloc]init];
// 1協(xié)議強引用
self.tool.delegate = self;
}
- (void)protacolTest:(NSString *)string{
NSLog(@"%@",string);
}
@property (nonatomic,strong)id <TestToolDelegate> delegate;
如果使用strong修飾則會造成循環(huán)引用
所以我們使用weak修飾
@property (nonatomic,weak)id <TestToolDelegate> delegate;
2.Block
和協(xié)議代理的解釋也類似,Block是如何造成循環(huán)引用的呢
請看如下代碼
#import <Foundation/Foundation.h>
typedef void(^MyBlock)(NSString *string);
@interface TestTool : NSObject
@property (nonatomic,copy) MyBlock block;
- (void)testBlock:(void(^)(NSString *string))block;
@end
#import "TestTool.h"
@implementation TestTool
- (void)testBlock:(void (^)(NSString *))block{
// 如果不將block賦給self.block的話是不會造成循環(huán)引用的芹壕,可在有的情況下block不在此方法中傳值汇四,所以就需要賦值了。
self.block = block;
// 做完一些事后block返回數(shù)據(jù)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
block(@"測試block");
});
});
}
@end
@interface ViewController ()<TestToolDelegate>
@property (nonatomic,strong)TestTool *tool;
@end
@implementation ViewController1
- (void)viewDidLoad {
[super viewDidLoad];
self.tool = [[TestTool alloc]init];
[self.tool testBlock:^(NSString *string) {
NSLog(@"%@",string);
// 如果此時直接使用self的話踢涌,就會造成循環(huán)引用
self.view.backgroundColor = [UIColor whiteColor];
}];
}
正確的使用方法是用weak修飾self通孽;
@interface ViewController ()<TestToolDelegate>
@property (nonatomic,strong)TestTool *tool;
@end
@implementation ViewController1
- (void)viewDidLoad {
[super viewDidLoad];
self.tool = [[TestTool alloc]init];
__weak typeof(self) weakSelf = self;
[self.tool testBlock:^(NSString *string) {
NSLog(@"%@",string);
// 如果此時直接使用self的話,就會造成循環(huán)引用
weakSelf.view.backgroundColor = [UIColor whiteColor];
}];
}
還是用圖理解一下吧
3.兩個類之間的循環(huán)引用
一個類是ViewController睁壁,一個類是TestTool. ViewController中先強引用了TestTool對象背苦,然后TestTool中也強引用了一個對象ViewController.這樣就造成了循環(huán)引用。
#import <Foundation/Foundation.h>
@interface TestTool : NSObject
@property (nonatomic,strong) id ID;
@end
@interface ViewController ()
@property (nonatomic,strong)TestTool *tool;
@end
@implementation ViewController1
- (void)viewDidLoad {
[super viewDidLoad];
self.tool = [[TestTool alloc]init];
self.tool.ID = self;
}
圖解
4.定時器NSTimer
@interface ViewController ()
@property (nonatomic,strong) NSTimer *timer;
@end
@implementation ViewController1
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakSelf selector:@selector(timerClick) userInfo:nil repeats:YES];
}
- (void)timerClick{
NSLog(@"我在重復");
}
//是否調(diào)用dealloc方法潘明,沒有則造成了循環(huán)引用
- (void)dealloc {
NSLog(@"ViewController被銷毀了");
[self.timer invalidate];
}
開啟定時器以后, timerClick方法會一直執(zhí)行,即使dismiss此控制器以后,也是一直在打印,而且dealloc方法不會執(zhí)行.很明顯這是循環(huán)引用造成了內(nèi)存泄露,控制器不會被釋放.
解決辦法:由于循環(huán)引用的起因是target,則可以包裝一個target,讓target是另一個對象,而不是ViewController即可行剂,其實NSTimer有一個類方法是Block創(chuàng)建的,親測不會造成循環(huán)引用
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
weakSelf.view.backgroundColor = [UIColor yellowColor];
}];
}
備注:
如果有不足或者錯誤的地方還望各位讀者批評指正钳降,可以評論留言厚宰,筆者收到后第一時間回復。
QQ/微信:976971956/ljh976971956遂填。
簡書號:超級卡布達
感謝各位觀眾老爺?shù)拈喿x铲觉,如果覺得筆者寫的還湊合,可以關(guān)注或收藏一下吓坚,不定期分享一些好玩的實用的demo給大家撵幽。
文/超級卡布達(簡書作者)
著作權(quán)歸作者所有,轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)礁击,并標注“簡書作者”盐杂。