[英]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.