iOS循環(huán)引用深入理解

循環(huán)引用也就是引用之后造成的一個(gè)循環(huán)用圖理解吧


image.png

下面是可能造成循環(huán)引用的幾種情況

1.協(xié)議代理

都知道協(xié)議的代理對(duì)象都用weak修飾,哪為何不用strong,或者copy呢?答案是會(huì)造成循環(huán)引用。下面就用代碼解釋吧

#import <Foundation/Foundation.h>
//協(xié)議
@protocol TestToolDelegate <NSObject>
- (void)protacolTest:(NSString *)string;
@end

@interface TestTool : NSObject
//使用strong會(huì)造成循環(huán)引用
@property (nonatomic,strong)id <TestToolDelegate> delegate;
@end

上面是聲明的協(xié)議,下面是一個(gè)類對(duì)象,類對(duì)象里強(qiáng)引用了delegate對(duì)象
下面來看下TestTool的使用

@interface ViewController ()<TestToolDelegate>
@property (nonatomic,strong)TestTool *tool;
@end
@implementation ViewController1

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tool = [[TestTool alloc]init];
//    1協(xié)議強(qiáng)引用
    self.tool.delegate = self;
}
- (void)protacolTest:(NSString *)string{
    NSLog(@"%@",string);
}

@property (nonatomic,strong)id <TestToolDelegate> delegate;
如果使用strong修飾則會(huì)造成循環(huán)引用
所以我們使用weak修飾
@property (nonatomic,weak)id <TestToolDelegate> delegate;


image.png
2.Block

和協(xié)議代理的解釋也類似,Block是如何造成循環(huán)引用的呢
請(qǐng)看如下代碼

#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ì)造成循環(huán)引用的,可在有的情況下block不在此方法中傳值,所以就需要賦值了。
        self.block = block;
//      做完一些事后block返回?cái)?shù)據(jù)
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            dispatch_sync(dispatch_get_main_queue(), ^{
                block(@"測(cè)試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);
//     如果此時(shí)直接使用self的話,就會(huì)造成循環(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);
//     如果此時(shí)直接使用self的話,就會(huì)造成循環(huán)引用
        weakSelf.view.backgroundColor = [UIColor whiteColor];
    }];
}

還是用圖理解一下吧


image.png
3.兩個(gè)類之間的循環(huán)引用

一個(gè)類是ViewController,一個(gè)類是TestTool. ViewController中先強(qiáng)引用了TestTool對(duì)象,然后TestTool中也強(qiáng)引用了一個(gè)對(duì)象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;
}

圖解


image.png
4.定時(shí)器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(@"我在重復(fù)");
}
//是否調(diào)用dealloc方法,沒有則造成了循環(huán)引用
- (void)dealloc {
    NSLog(@"ViewController被銷毀了");
    [self.timer invalidate];
}

開啟定時(shí)器以后, timerClick方法會(huì)一直執(zhí)行,即使dismiss此控制器以后,也是一直在打印,而且dealloc方法不會(huì)執(zhí)行.很明顯這是循環(huán)引用造成了內(nèi)存泄露,控制器不會(huì)被釋放.


image.png

解決辦法:由于循環(huán)引用的起因是target,則可以包裝一個(gè)target,讓target是另一個(gè)對(duì)象,而不是ViewController即可,其實(shí)NSTimer有一個(gè)類方法是Block創(chuàng)建的,親測(cè)不會(huì)造成循環(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];
    }];
}
image.png

代碼示例

備注:

如果有不足或者錯(cuò)誤的地方還望各位讀者批評(píng)指正,可以評(píng)論留言,筆者收到后第一時(shí)間回復(fù)。

QQ/微信:976971956/ljh976971956。

簡(jiǎn)書號(hào):超級(jí)卡布達(dá)

感謝各位觀眾老爺?shù)拈喿x,如果覺得筆者寫的還湊合,可以關(guān)注或收藏一下,不定期分享一些好玩的實(shí)用的demo給大家。

文/超級(jí)卡布達(dá)(簡(jiǎn)書作者)

著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),并標(biāo)注“簡(jiǎn)書作者”。

?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,666評(píng)論 1 32
  • 面向?qū)ο蟮娜筇卣?并作簡(jiǎn)單的介紹。 面向?qū)ο蟮娜齻€(gè)基本特征是:封裝、繼承、多態(tài)。 1.封裝是面向?qū)ο蟮奶卣髦?...
    xiny123閱讀 1,643評(píng)論 0 6
  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,597評(píng)論 0 6
  • 2019年3月27日 周四 晚上,妹夫打電話問我睡了嗎?,我說沒有。他說找我商量點(diǎn)事,問我方便嗎?我說沒問...
    寒梅hm閱讀 913評(píng)論 1 18
  • 如何管理超大虛擬地址空間? 方法一:多級(jí)頁(yè)表 關(guān)鍵:避免一直將所有頁(yè)表都保存在內(nèi)存,尤其不應(yīng)該將不需要的頁(yè)表還保存...
    橡樹人閱讀 978評(píng)論 0 1

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