国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - IOS - iOS block循環引用詳解及常見誤區

iOS block循環引用詳解及常見誤區

2021-12-27 15:39俊華的博客 IOS

這篇文章主要介紹了iOS block循環引用詳解和應用,常見誤區詳解,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下

Block循環引用

什么情況下block會造成循環引用

ARC 情況下 block為了保證代碼塊內部對象不被提前釋放,會對block中的對象進行強引用,就相當于持有了其中的對象,而如果此時block中的對象又持有了該block,就會造成循環引用。

常見誤區

誤區一.所有block都會造成循環引用

在block中,并不是所有的block都會循造成環引用,比如UIView動畫block、Masonry添加約束block、AFN網絡請求回調block等。    

1. UIView動畫block不會造成循環引用是因為這是類方法,不可能強引用一個類,所以不會造成循環引用。    

2. Masonry約束block不會造成循環引用是因為self并沒有持有block,所以我們使用Masonry的時候不需要擔心循環引用。

Masonry內部代碼

?
1
2
3
4
5
6
7
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    //這里并不是self.block (self并沒有持有block 所以不會引起循環引用)
    block(constraintMaker);
    return [constraintMaker install];
}

3.AFN請求回調block不會造成循環引用是因為在內部做了處理。
block先是被AFURLSessionManagerTaskDelegate對象持有。而AFURLSessionManagerTaskDelegate對象被mutableTaskDelegatesKeyedByTaskIdentifier字典持有,在block執行完成后,mutableTaskDelegatesKeyedByTaskIdentifier字典會移除AFURLSessionManagerTaskDelegate對象,這樣對象就被釋放了,所以不會造成循環引用。

AFN內部代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#pragma mark - 添加代理
- (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;
     //block被代理引用
    delegate.completionHandler = completionHandler;
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    //設置代理
    [self setDelegate:delegate forTask:dataTask];
 
    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}
#pragma mark - 設置代理
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);
 
    [self.lock lock];
    //代理被mutableTaskDelegatesKeyedByTaskIdentifier字典引用
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [delegate setupProgressForTask:task];
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}
#pragma mark - 任務完成
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    if (delegate) {
        //任務完成,移除
        [self removeDelegateForTask:dataTask];
        [self setDelegate:delegate forTask:downloadTask];
    }
 
    if (self.dataTaskDidBecomeDownloadTask) {
        self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
    }
}
#pragma mark - 移除任務代理
- (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];
}

誤區二.block中只有self會造成循環引用

在block中并不只是self會造成循環引用,用下劃線調用屬性(如_name)也會出現循環引用,效果和使用self是一樣的(內部會用self->name去查找)。

?
1
2
3
4
5
6
7
8
//會造成循環引用
_person1 = [[Person alloc] init];
_person2 = [[Person alloc] init];
_person2.name = @"張三";
    
[_person1 Block:^{
    NSLog(@"%@",_person2.name)
}];

誤區三.通過__weak __typeof(self) weakSelf = self;可以解決所有block造成的循環引用

大部分情況下,這樣使用是可以解決block循環引用,但是有些情況下這樣使用會造成一些問題,比如在block中延遲執行一些代碼,在還沒有執行的時候,控制器被銷毀了,這樣控制器中的對象也會被釋放,__weak對象就會變成null。所以會輸出null。

?
1
2
3
4
5
6
7
8
9
10
//在延遲執行期間,控制器被釋放了,打印出來的會是**(null)**
_person1 = [[Person alloc] init];
_person2 = [[Person alloc] init];
_person2.name = @"張三";
__weak __typeof(self) weakSelf = self;
[_person1 Block:^{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",weakSelf.person2.name);
    });
}];

誤區四.用self調用帶有block的方法會引起循環引用

并不是所有通過self調用帶有block的方法會引起循環引用,需要看方法內部有沒有持有self。

?
1
2
3
4
//不會引起循環引用
[self dismissViewControllerAnimated:YES completion:^{
    NSLog(@"%@",self.string);
}];

如何避免循環引用

方式一、weakSelf、strongSelf結合使用

使用weakSelf結合strongSelf的情況下,能夠避免循環引用,也不會造成提前釋放導致block內部代碼無效。

?
1
2
3
4
5
6
7
8
9
10
_person1 = [[Person alloc] init];
_person2 = [[Person alloc] init];
_person2.name = @"張三";
__weak __typeof(self) weakSelf = self;
[_person1 Block:^{
    __typeof(&*weakSelf) strongSelf = weakSelf;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",strongSelf.person2.name);
    });
}];

方式二、block的外部對象使用week

外部對象通過week修飾,使用全局弱指針指向一個局部強引用對象,這樣局部變量在超出其作用域后也不會被銷毀,因為是弱指針,所以不會造成循環引用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@interface CLViewController ()
//弱引用指針
@property (nonatomic,weak) Person *person1;
@property (nonatomic,strong) Person *person2;
 
@end
 
@implementation CLViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    //局部強引用對象
    Person *person1 = [[Person alloc] init];
    _person1 = person1;
    
    
    _person2 = [[Person alloc] init];
    _person2.name = @"張三";
    [_person1 Block:^{
            NSLog(@"%@",self.person2.name);
    }];
 
}

方式三.將對象置為nil

使用完對象之后就沒有必要再保留該對象了,將對象置為nil。在ARC中,被置為nil的對象會被銷毀。雖然這樣也可以達到破除循環引用的效果,但是這樣使用起來很不方便,如果一個對象有多個block,在前面將對象置空,后面的block就不會執行,所以使用這種方法來防止循環引用,需要注意在合適的位置將對象置空。

?
1
2
3
4
5
6
7
8
9
10
11
12
_person1 = [[Person alloc] init];
_person2 = [[Person alloc] init];
_person2.name = @"張三";
[_person1 Block:^{
    NSLog(@"%@",self.person2.name);
    //置空,避免循環引用
    _person1 = nil;
}];
//由于上面已經將對象置空,所以這里block里邊的代碼不會執行
[_person1 Block:^{
    NSLog(@"%@",self.person2.name);
}];

雖然這種方式使用起來不是很友好,但是在封裝block的時候,可以考慮使用完馬上置空當前使用的block,這樣使用的時候就不需要考慮循環引用的問題。

?
1
2
3
4
5
6
7
8
9
- (void)back
{
    if (self.BackBlock)
    {
        self.BackBlock(button);
    }
//使用完,馬上置空當前block
    self.BackBlock = nil;
}

總結

使用block的時候,我們首先需要做的就是判斷當前block是否會引起循環引用,如果會引起循環引用,再考慮采取哪種方式來避免循環引用。

到此這篇關于iOS block循環引用詳解和應用的文章就介紹到這了,更多相關iOS block循環引用內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/junhuawang/p/15167935.html

延伸 · 閱讀

精彩推薦
  • IOSiOS開發技巧之狀態欄字體顏色的設置方法

    iOS開發技巧之狀態欄字體顏色的設置方法

    有時候我們需要根據不同的背景修改狀態欄字體的顏色,下面這篇文章主要給大家介紹了關于iOS開發技巧之狀態欄字體顏色的設置方法,文中通過示例代碼...

    夢想家-mxj8922021-05-10
  • IOS詳解iOS中多個網絡請求的同步問題總結

    詳解iOS中多個網絡請求的同步問題總結

    這篇文章主要介紹了詳解iOS中多個網絡請求的同步問題總結,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    liang199111312021-03-15
  • IOSiOS實現控制屏幕常亮不變暗的方法示例

    iOS實現控制屏幕常亮不變暗的方法示例

    最近在工作中遇到了要將iOS屏幕保持常亮的需求,所以下面這篇文章主要給大家介紹了關于利用iOS如何實現控制屏幕常亮不變暗的方法,文中給出了詳細的...

    隨風13332021-04-02
  • IOSiOS中UILabel實現長按復制功能實例代碼

    iOS中UILabel實現長按復制功能實例代碼

    在iOS開發過程中,有時候會用到UILabel展示的內容,那么就設計到點擊UILabel復制它上面展示的內容的功能,也就是Label長按復制功能,下面這篇文章主要給大...

    devilx12792021-04-02
  • IOSiOS中MD5加密算法的介紹和使用

    iOS中MD5加密算法的介紹和使用

    MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。對輸入信息生成唯一的128位散列值(32個字符)。這篇文...

    LYSNote5432021-02-04
  • IOSiOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    這篇文章主要介紹了iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果的相關資料,需要的朋友可以參考下...

    jiangamh8882021-01-11
  • IOSiOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)

    iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和

    這篇文章主要介紹了iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)的相關資料,需要的朋友可以參考下...

    CodingFire13652021-02-26
  • IOSiOS開發之視圖切換

    iOS開發之視圖切換

    在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在iOS開發中常用的視圖切換有三種,今天我們將...

    執著丶執念5282021-01-16
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 精品国产欧美 | 久久久久久网站 | 欧美黄色网页 | 求av网址 | 青娱乐自拍偷拍 | 精品香蕉一区二区三区 | 伦一区二区三区中文字幕v亚洲 | 亚洲国产精品电影在线观看 | 91麻豆精品国产91久久久久久 | 精品视频网 | 在线播放国产一区二区三区 | 综合网激情五月 | 黄色电影天堂 | 欧美在线a| 黄色片网站视频 | 日韩理伦片在线观看视频播放 | 老熟女毛片 | www.久久.com | 精品一区二区三区免费 | 国产美女一区二区三区 | 日韩一区二区三区视频 | 精品欧美乱码久久久久久 | 久久久中文字幕 | 亚洲 成人 av | 亚州中文字幕蜜桃视频 | 91在线精品一区二区 | 亚洲精品国产成人 | 国产精品一区二区不卡 | 久久99综合久久爱伊人 | 国产情侣av自拍 | 97超碰青青草| 久久九九99| 色婷婷精品国产一区二区三区 | 欧美日韩91 | 日本精品一区二区三区在线观看视频 | 香蕉yeye凹凸一区二区三区 | 成人在线看片 | yy6080久久伦理一区二区 | 极品国产在线 | 亚洲二区视频 | av中文字幕在线播放 |