1、引發內存泄露
假設一個類有兩個屬性:block和name;
//
// PHBlockTest.h
// BlockTestTest
//
// Created by 項普華 on 2017/2/9.
// 郵箱: [email protected]
// 電話: +86 13316987488
// 主頁: https://github.com/xphaijj
// Copyright © 2017年 項普華. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface PHBlockTest : NSObject
@property (nonatomic, copy) void(^block)();
@property (nonatomic, copy) NSString *name;
@end
//
// PHBlockTest.m
// BlockTestTest
//
// Created by 項普華 on 2017/2/9.
// 郵箱: [email protected]
// 電話: +86 13316987488
// 主頁: https://github.com/xphaijj
// Copyright © 2017年 項普華. All rights reserved.
//
@implementation PHBlockTest
- (id)init
{
if (self = [super init]) {
self.block = ^{
NSLog(@"%@",_name);
NSLog(@"%@",self->_name);
NSLog(@"%@",self.name);
};
}
return self;
}
@end
普通情況下,block是存在於棧中的,意味着其生命週期由系統管理,不需要我們手動管理。這就存在一個問題,就是我們如果使用block保存一段代碼塊,在回調的時候,說不定已經被系統回收了。
因此我們需要想辦法將block存儲到堆中,方法就是使用copy,做一次複製。(如果使用retain的話,只會將其計數器加一,多做一次強引用,不會重新分類新的內存,所以依然存在於棧中)。 如上代碼塊中的m文件中的
NSLog(@"%@",_name);
NSLog(@"%@",self->_name);
NSLog(@"%@",self.name);
,此時如果在block中調用持有它的對象,就會產生循環引用,造成內存泄露。這個問題怎麼引起的呢? 因爲block存在於堆中,在其代碼塊中引用的對象都會產生一個強指針,而這個時候block本身就是被其引用的對象(copy)強指針指着。這樣就造成了雙方都無法釋放,從而造成內存泄露。解決方案如下:
//
// PHBlockTest.m
// BlockTestTest
//
// Created by 項普華 on 2017/2/9.
// 郵箱: [email protected]
// 電話: +86 13316987488
// 主頁: https://github.com/xphaijj
// Copyright © 2017年 項普華. All rights reserved.
//
@implementation PHBlockTest
- (id)init
{
if (self = [super init]) {
__unsafe_unretained PHBlockTest *temp = self;
//__weak PHBlockTest *temp = self;
self.block = ^{
NSLog(@"%@", temp->_name);
NSLog(@"%@", temp.name);
};
}
return self;
}
@end
很多時候我使用的是下面的代碼:
__weak PHBlockTest *temp = self;
和上面的
__unsafe_unretained PHBlockTest *temp = self;
有什麼區別呢?
簡單說就是,unsafe,爲什麼不安全呢?因爲當其所修飾的對象釋放時,它並不知道,所以,其地址依然存在,不會清爲nil,這樣第七行代碼
temp->_name
是可以訪問的(在使用時也應當注意這個細節),而使用weak修飾的話,當其修飾的對象被釋放時,temp會被清爲nil,這樣就會出現nil->_name的情況.這是不允許的.
如果想要了解
__unsafe_unretained和__weak的具體區別的話,可查閱其它資料.
爲了防止上面所說的weak釋放問題還有下面一種寫法:
//
// PHBlockTest.m
// BlockTestTest
//
// Created by 項普華 on 2017/2/9.
// 郵箱: [email protected]
// 電話: +86 13316987488
// 主頁: https://github.com/xphaijj
// Copyright © 2017年 項普華. All rights reserved.
//
@implementation PHBlockTest
- (id)init
{
if (self = [super init]) {
__weak PHBlockTest *temp = self;
self.block = ^{
__strong PHBlockTest *strongSelf = temp;//防止在下面使用temp的時候 temp被釋放掉
NSLog(@"%@", strongSelf->_name);
NSLog(@"%@", strongSelf.name);
};
}
return self;
}
@end