1. 程式人生 > >iOS block中使用self的那麼事

iOS block中使用self的那麼事

我們在使用block的時候,如果在block中使用self有可能會迴圈引用,產生記憶體洩漏的問題。

通常,我們如果遇到這種情況,我們會將self轉換成weak automatic的變數,這樣就避免了block對self強引用,即:

__weak typeof(self) weakSelf = self;
__weak __typeof__(self) weakSelf = self;
__weak __typeof(self) weakSelf = self;

以上三種寫法,任選一種都是可以的,typeof就是獲取變數的型別,沒別的深奧的東西。

但是,我在檢視AFNetworking原始碼的時候發現發現,在有的block中使用self

,作者並沒有將self轉化weakSelf,難道這樣不會引起記憶體洩漏的問題嗎?

為此,我做了相關的測試。講道理,如果存在記憶體洩漏,那麼dealloc方法就不會被呼叫。

測試一:

@property (copy, nonatomic) dispatch_block_t testBlock;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.testBlock = ^(){
        NSLog(@"%@", [self class]);
    };
    self.testBlock();
}

這塊我為了簡單,直接使用GCD

中的

typedef void (^dispatch_block_t)(void)

它是一個無引數,無返回值的block。
這個testBlock是控制器(以下用VC代替)的一個屬性。在block中直接使用self就會造成迴圈引用,Xcode也會做出相應的警告提示:

⚠️ Capturing self strongly in this block is likely to lead to a retain cycle.

這句話的意思就是說,此處的block強引用了self,會存在保留環,即迴圈引用,那麼VC的dealloc方法也不會被正常呼叫。這個時候我們就需要將其轉化為weakSelf

來打破這個保留環,避免記憶體洩漏。程式碼更正如下:

- (void)viewDidLoad {
    [super viewDidLoad];

    __weak typeof(self) weakSelf = self;

    self.testBlock = ^(){
        NSLog(@"%@", [weakSelf class]);
    };
    self.testBlock();
}

這樣VC的dealloc方法也可以正常被呼叫了。

結論:當block直接做為VC的屬性時,如果block內部沒有使用weakSelf,則會造成迴圈引用,導致記憶體洩漏。

測試二:

- (void)viewDidLoad {
    [super viewDidLoad];

    __weak typeof(self) weakSelf = self;

    self.testBlock = ^(){
        [weakSelf doSomething];
    };
    self.testBlock();
}

- (void)doSomething {
    NSLog(@"%@", [self class]);
}

測試發現VC的dealloc方法被正常呼叫。

結論:當在block中呼叫一個方法,並且這個方法中直接或者間接的使用self,不會出現記憶體洩漏的問題。

測試三:

- (void)viewDidLoad {
    [super viewDidLoad];

    dispatch_block_t block = ^(){
        [self doSomething];
    };
    block();
}

- (void)doSomething {
    NSLog(@"%@", [self class]);
}

測試發現VC的dealloc方法被正常呼叫,所以我們在使用GCD的時候,大部分情況都不需要做轉換。

結論:當block不是self的屬性時,block記憶體使用self不會造成記憶體洩漏的問題。

測試四:

- (void)viewDidLoad {
    [super viewDidLoad];

    Class VC = self.class;
    [VC doSomethingWithBlock:^{
        [self doSomething];
    }];
}

+ (void)doSomethingWithBlock:(dispatch_block_t)block {
    if (block) {
        block();
    }
}

- (void)doSomething {
    NSLog(@"%@", [self class]);
}

測試發現VC的dealloc方法被正常呼叫,我們在使用UIView有關動畫的類方法時,大部分情況都不需要做轉換。

結論:當使用類方法,並且類方法中用block做引數時,block內部使用self也不會造成記憶體洩漏的問題。

通過這麼多的測試,我們可以看到,當且僅當block直接或間接的被self持有時,如果不做weakSelf轉換,就會有記憶體洩漏的風險。

最後補充一點,同樣在檢視AFNetworking的時候,遇到有時候還需要轉化成strongSelf的情況:

 __weak __typeof(self) weakSelf = self;

NSURLSessionDataTask *dataTask = nil;
dataTask = [self.sessionManager GET:request.URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        __strong __typeof(weakSelf) strongSelf = weakSelf;
        sf_dispatch_main_async_safely(^{
            if (success) {
                success((NSHTTPURLResponse *)task.response, responseObject);
            }
            [strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:task.currentRequest.URL];
            if ([strongSelf.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
                [strongSelf.delegate webViewDidFinishLoad:strongSelf];
            }
        });
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        sf_dispatch_main_async_safely(^{
            if (failure) {
                failure(error);
            }
        });
  }];

那麼什麼情況下,需要將weakSelf轉化成strongSelf呢 ?

由於__weak變數的特殊性,會在物件銷燬後自動置為nil,如果在block中多次需要訪問self,就需要轉化為strong automatic,確保在block使用期間,self不會被釋放。

相關推薦

iOS block使用self那麼

我們在使用block的時候,如果在block中使用self有可能會迴圈引用,產生記憶體洩漏的問題。 通常,我們如果遇到這種情況,我們會將self轉換成weak automatic的變數,這樣就避免了block對self強引用,即: __weak typeof

iOS Block 迴圈引用的解決

前言: 在iOS 中使用block 時 ,如果稍微不注意,則很容易 導致 迴圈引用 導致記憶體洩漏 二者都無法釋放 。出現記憶體洩漏。 #import <Foundation/Foundation.h> typedefvoid (^EOCNetworkFet

講述Sagit.Framework解決:雙向引用導致的IOS記憶體洩漏(下)- block任性用self

前言: 發現業務程式碼有一個地方的記憶體沒釋放,原因很也簡單: 在block裡用到了self,造成雙向引用,然後就開始思考怎麼處理這個問題。 常規則思維,就是改程式碼,block不要用到self,或只用self的弱引用。 只是框架這裡特別,有一個特好用的系列,STLastXXX系列,是用巨集定

iOSself.property 和_property的區別,init和dealloc為何避免用self.property

一、self.property訪問 1、self.property 經過oc訊息派發,可以完成屬性所定義的“記憶體管理語義”, 例如copy屬性; 2、通過屬性訪問,可以設定斷點除錯。   二、_property直接訪問例項變數 1、_property直接訪問例項變

iOS開發-多層巢狀block如何使用__weak和__strong

1、關於__weak __weak只能在ARC模式下使用,也只能修飾物件(比如NSString等),不能修飾基本資料型別(比如int等) __weak修飾的物件在block中不可以被重新賦值。 __weak只在ARC下使用,可以避免迴圈引用。 __weak修飾物

iOS開發Block的理解與使用

// 隨機生成的顏色 UIColor *color = [UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1]; // 第二步 給Blo

精通iOS開發--第15章 Grand Central Dispatch和後臺處理之BlockSelf的迴圈引用

Block與Self的迴圈引用 01:眾所周知若self中引用了Block塊,而此Block塊中又引用了Self則會造成迴圈引用,需要提醒的是即使在你的block程式碼中沒有顯式地出現"s

IOS學習】到底什麼時候才需要在ObjC的Block使用weakSelf/strongSelf

Objective C 的 Block 是一個很實用的語法,特別是與GCD結合使用,可以很方便地實現併發、非同步任務。但是,如果使用不當,Block 也會引起一些迴圈引用問題(retain cycle)—— Block 會 retain ‘self’,而 ‘self‘

iOS開發ARC的那點

        在MRC時代,Block會隱式地對進入其作用域內的物件(或者說被Block捕獲的指標指向的物件)加retain,來確保Block使用到該物件時,能夠正確的訪問。 這件事情在下面程式碼展示的情況中要更加額外小心。 MyViewController *myController = [[MyV

Blockweak/strong self的用法

在用到block時,我們經常會有這樣一種用法 //請忽略不重要的程式碼行 __weak __typeof(self)weakSelf = self; blk_t blk = ^() { __strong __typeof(weakSelf)stro

iOS面試題(2.)關於在block使用weakSelf的討論

問題 我們知道,在使用 block 的時候,為了避免產生迴圈引用,通常需要使用 weakSelf 與 strongSelf,寫下面這樣的程式碼: __weak typeof(self) weakSelf = self; [self doSomeBlockJob:^{

iOS開發block的寫法簡單整理

約定:用法中的符號含義列舉如下: return_type表示返回的物件/關鍵字等(可以是void,並省略) blockName表示block的名稱 var_type表示引數的型別(可以是void,並省略) varName表示引數名稱 1.1 Blo

iosself的用法

最近有人問我關於什麼時候用self.賦值的問題, 我總結了一下, 發出來給大家參考. 有什麼問題請大家斧正.     關於什麼時間用self. , 其實是和Obj-c的存取方法有關, 不過網上很多人也都這麼解答的, 那它為什麼和存取方法有關? 怎麼有關的? 並沒有多少人回答

iOS開發 new與alloc/init的區別 及 [NSArray array] 和 [[NSArray alloc]init] 及 self. 和 _ 的區別

專案過程中,想到這幾個概念的區別有些模糊,於是縱觀各種資料,來篇博文為自己記錄下,也為小夥伴們說說我的理解。 [className new] 和 [[className alloc] init] 的區別 1.在實際開發中很少會用到new,一般建立物件咱們看到的全

【程式碼筆記】iOS-在Block修改外部變數值的

一,程式碼。 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loadin

ios開發類方法與例項方法區別 以及self有什麼不同

Objective-C裡面既有例項方法也類方法。類方法(Class Method) 有時被稱為工廠方法(Factory Method)或者方便方法(Convenience method)。工廠方法的稱謂明顯和一般意義上的工廠方法不同,從本質上來說,類方法可以獨立於物件而執行,所以在其他的語言裡面類方法有的

iOS 開發的訊息機制-代理、通知、block

關於代理 1.代理時一種設計模式。 使用場景:如果物件B要監聽物件A裡面發什麼了什麼,使用代理。如果物件A想讓物件B去幹活,使用代理。如果物件A中的按鈕或者cell被點選,要把相應的資料傳遞給物件B,使用代理。例如,我們自定義view裡面的button被點選,需要讓控制器知

IOS Block用法進階二 區域性變數和全域性變數在Block的使用

一、區域性變數與block塊 先看下面程式碼: int number=100; void (^TestBlock)(int)=^(int x){ number=number+x; }; TestBl

iOS開發地圖與定位

視圖 編寫 aps 簡單 -a 第三方 span spa margin   不管是QQ還是微信的移動client都少不了定位功能,之前在微信demo中沒有加入定位功能,今天就寫個定位的小demo來了解一下定位和地圖的東西。地圖和定位看上去是挺高大上一東西。其有使用方法比

iOS開發,獲取iOS設備型號

bsp ios設備型號 isequal uid eve ide inf turn res 1、首先要導入頭文件   #import <sys/utsname.h> 2、代碼如下 - (NSString *)getDeviceVersionInfo{