AFNetwork 使用中遇到的坑,循環(huán)引用

最近在寫一個(gè) SDK ,用到了 AFNetwork,其中有一段代碼如下:

...
@property(nonatomic,strong)AFHTTPSessionManager *request;
....
-(void)excute{
    ...
    @weakify(self);
    [self.request POST:self.api.APIPath
            parameters:self.api.params
              progress:nil
               success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                   @strongify(self);
                   [self handelResponseComplete:responseObject];
               }
               failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                   @strongify(self);
                   [self handelResponseError:error];
               }];
    ...
}

本以為沒問題,結(jié)果每次使用才發(fā)現(xiàn),回調(diào)中的 self 已經(jīng)被釋放了.想了一下,還真是,由于這個(gè)類在使用中是被作為臨時(shí)變量來使用的,生命周期一結(jié)束,沒有強(qiáng)引用,就完蛋了.由于想要先寫一點(diǎn)功能,就干脆直接把@strongify(self);去掉了,直接上,這次倒不會(huì)被釋放,倒是老覺得會(huì)循環(huán)引用.
始終還是不放心,在-dealoc方法中加上打印輸出,看看代碼.
突然發(fā)現(xiàn),居然會(huì)正常釋放!
這還了得,趕緊看看是不是哪里弄錯(cuò)了.找了半天好像也沒找到我哪里寫錯(cuò)了,還是看看 AFNetwork 源代碼吧.
,先來看看這個(gè)post方法

- (NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(id)parameters
                      progress:(void (^)(NSProgress * _Nonnull))uploadProgress
                       success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                       failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];

    [dataTask resume];

    return dataTask;
}

再一路跟進(jìn),到了AFURLSessionManager的這個(gè)方法

- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
                uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
              downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
             completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

這里創(chuàng)建了一個(gè)代理類,然后把 block 保存在代理類中,而代理類本身通過這個(gè)方法

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    [self.lock lock];
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [delegate setupProgressForTask:task];
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

存放在了一個(gè)字典屬性中.
來捋一捋
self(我自己代碼) -持有> requst(AFHTTPSessionManager)-持有>mutableTaskDelegatesKeyedByTaskIdentifier(字典)-持有>delegate-持有>block-持有>self(我自己代碼中的)
好大一個(gè)環(huán),不過這不還是一個(gè)環(huán)嗎?
不理解.
又來打斷點(diǎn)調(diào)試

調(diào)試

看到一個(gè)這個(gè)代碼

-URLSession:task:didCompleteWithError:

有一句[self removeDelegateForTask:task];這不剛剛和那個(gè)-setDelegate:forTask:對(duì)應(yīng)嗎?去看看代碼

- (void)removeDelegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    [self.lock lock];
    [delegate cleanUpProgressForTask:task];
    [self removeNotificationObserverForTask:task];
    [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
    [self.lock unlock];
}

果然, AFNetwork 在請(qǐng)求結(jié)束后會(huì)自動(dòng)釋放掉 delegate,打破那個(gè)環(huán),所以循環(huán)引用也就不存在了.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肥印,一起剝皮案震驚了整個(gè)濱河市橡娄,隨后出現(xiàn)的幾起案子罐柳,更是在濱河造成了極大的恐慌价脾,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帅刊,死亡現(xiàn)場(chǎng)離奇詭異走芋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)叉寂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門萍启,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屏鳍,你說我怎么就攤上這事勘纯。” “怎么了钓瞭?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵驳遵,是天一觀的道長。 經(jīng)常有香客問我降淮,道長超埋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任佳鳖,我火速辦了婚禮霍殴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘系吩。我一直安慰自己来庭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布穿挨。 她就那樣靜靜地躺著月弛,像睡著了一般肴盏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帽衙,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天菜皂,我揣著相機(jī)與錄音,去河邊找鬼厉萝。 笑死恍飘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谴垫。 我是一名探鬼主播章母,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翩剪!你這毒婦竟也來了乳怎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤前弯,失蹤者是張志新(化名)和其女友劉穎蚪缀,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體博杖,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椿胯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了剃根。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡前方,死狀恐怖狈醉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惠险,我是刑警寧澤苗傅,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站班巩,受9級(jí)特大地震影響渣慕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抱慌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一逊桦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抑进,春花似錦强经、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兰迫。三九已至,卻和暖如春炬称,著一層夾襖步出監(jiān)牢的瞬間汁果,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工玲躯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留据德,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓府蔗,卻偏偏與公主長得像晋控,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子姓赤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容