簡體   English   中英

Objective-C創建弱塊以檢查內存釋放

[英]Objective-C creating weak block to check memory release

我已經讀過,如果將新對象分配給弱屬性,則分配后該對象將被釋放。 即使是來自編譯器的警告也是一樣。

@interface RetainCycleObjCViewController ()
{
}
@property (nonatomic, weak) void (^weakBlock)(void);
@end

@implementation RetainCycleObjCViewController
- (void)viewDidLoad {
    [super viewDidLoad];

 _weakBlock = ^void{
        NSLog(@"Execution inside a weakBlock");
    };

_weakBlock();
}
@end

我對weakBlock收到相同的警告: 將塊文字分配給弱變量; 分配后將釋放對象

但是,當我在下一行執行_weakBlock()時,它仍會打印該語句。 這怎么可能? 因為給定0引用計數,現在應該已經從內存中刪除了新創建的塊對象?

您實際上並沒有在該代碼中分配塊。 塊的主體都是靜態內容; 編譯后沒有任何變化。

如果您這樣做:

    _weakBlock = ^void{
        NSLog(@"Execution inside a weakBlock");
    };
    NSLog(@"%@", [_weakBlock class]);

您會看到以下內容:

2018-10-21 09:33:48.827423-0500 kdkdkdkds[9367:1777827] __NSGlobalBlock__

編譯器認識到該塊不會捕獲任何在運行時可能發生變化的內容,因此,創建了一個永遠不會分配的全局靜態塊。

就像@Brandon在評論中說的那樣,如果您在作用域中聲明了一個局部變量並導致分配了堆棧塊,那么直到作用域結束時,這種情況才會消失。

@autoreleasepool {
    void __weak (^_weakBlock)(void);
    int k = 2;
    _weakBlock = ^void{
        NSLog(@"Execution inside a weakBlock (%d)", k);
    };
    NSLog(@"C; %@", [_weakBlock class]);
    NSLog(@"P; %p", _weakBlock);
}
2018-10-21 09:36:31.585458-0500 kdkdkdkds[9392:1780803] C; __NSStackBlock__
2018-10-21 09:36:31.586291-0500 kdkdkdkds[9392:1780803] P; 0x7ffeefbff4c0

現在,實例變量分配會稍稍更改規則,因為您的分配超出了范圍。

@interface SpongeBob:NSObject
@end

@interface SpongeBob ()
{
}
@property (nonatomic, weak) void (^weakBlock)(void);
@end

@implementation SpongeBob
- (instancetype)init
{
    self = [super init];
    if (self) {
        int k = 2;
        _weakBlock = ^void{
            NSLog(@"Execution inside a weakBlock (%d)", k);
        };
        NSLog(@"C; %@", [_weakBlock class]);
        NSLog(@"P; %p", _weakBlock);
    }
    return self;
}
@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [[SpongeBob alloc] init];
    }
    return 0;
}

2018-10-21 09:43:39.518545-0500 kdkdkdkds[9480:1787889] C; __NSStackBlock__
2018-10-21 09:43:39.518883-0500 kdkdkdkds[9480:1787889] P; 0x7ffeefbff488

等待。 什么? 如果該值確實分配給了ivar,那么這就是定時炸彈。 因此,讓我們嘗試一下:

如果我們添加:

- (void)squarePants
{
    NSLog(@"C; %@", [_weakBlock class]);
    NSLog(@"P; %p", _weakBlock);
}

然后調用它:

    SpongeBob *bob = [[SpongeBob alloc] init];
    [bob squarePants];

正如預期的那樣,它崩潰了,因為堆棧塊不再像init的作用域一樣有效

(這似乎很卑鄙。然后,再次消除警告,崩潰就消失了。)

現在,如果您復制分配時的塊,則分配時的立即解除分配確實會開始:

    _weakBlock = [^void{
        NSLog(@"Execution inside a weakBlock (%d)", k);
    } copy];

2018-10-21 09:48:04.295762-0500 kdkdkdkds[9510:1792549] C; (null)
2018-10-21 09:48:04.296167-0500 kdkdkdkds[9510:1792549] P; 0x0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM