一.Block在MRC下的内存管理:
void(^myBlock)() = ^{
NSLog(@"--");
};
myBlock();
- 默认情况下,Block的内存存储在栈中,不需要开发人员对其进行内存管理
- 当Block变量出了作用域,Block的内存会被自动释放
Person *p = [[Person alloc] init];
void(^myBlock)()=^{
NSLog(@"--%@--",p);
};
myBlock();
[p release];//Person对象在这里可以正常被释放.
- 在Block的内存存储在栈中时,如果在Block中引用了外面的对象,不会对所引用的对象进行任何操作
void(^myBlock)() = ^{
NSLog(@"----");
};
myBlock();
Block_copy(myBlock);
//做一些事情
记得释放
Block_release(myBlock);
如果对Block进行一次copy操作,那么Block的内存会被移动到堆中,这时需要开发人员对其进行release操作来管理内存
Person *p = [[Person alloc] init];
void(^myBlock)() = ^{
NSLog(@"%@",p);
};
myBlock();
Block_copy(myBlock);
//做一些事情
Block_release(myBlock);
[p release];
Person对象在这里无法正常被释放,因为p在Block中被进行了一次retain操作
- 如果对Block进行一次copy操作,那么Block的内存会被移动到堆中,在Block的内存存储在堆中时,如果在Block中引用了外面的对象,会对所引用的对象进行一次retain操作,即使在Block自身调用了release操作之后,Block也不会对所引用的对象进行一次release操作,这时会造成内存泄漏
__block Person *p = [[Person alloc] init];
void(^myBlock)() = ^{
NSLog(@"%@",p);
};
myBlock();
Block_copy(myBlock);
//做一些事情
Block_release(myBlock);
[p release]; Person对象在这里可以正常被释放
- 1.如果对Block进行一次copy操作,那么Block的内存会被移动到堆中,在Block的内存存储在堆中时,如果在Block中引用了外面的对象,会对所引用的对象进行一次retain操作,为了不对所引用的对象进行一次retain操作,可以在对象的前面使用下划线下划线block来修饰
循环引用:
如果对象内部有一个Block属性,而在Block内部又访问了该对象,那么会造成循环引用
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^myBlock)();
@end
#import "Person.h"
@implementation Person
-(void)dealloc{
NSLog(@"Person dealloc");
Block_copy(_myBlock);
[super dealloc];
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
Person *p = [[Person alloc] init];
p.myBlock = ^{
NSLog(@"%@",p);
};
p.myBlock();
[p release];
NSLog(@"%ld",[p retainCount]);
return 0;
}
//结果
2018-07-29 22:18:17.530846+0800 blocks[11948:533963] <Person: 0x100609280>
2018-07-29 22:18:17.531194+0800 blocks[11948:533963] 1
情况2:
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
- (void)resetBlock;
@end
@implementation Person
- (void)resetBlock
{
self.myBlock = ^{
NSLog(@"------%@", self);
};
}
- (void)dealloc
{
NSLog(@"Person dealloc");
Block_release(_myBlock);
[super dealloc];
}
@end
Person *p = [[Person alloc] init];
[p resetBlock];
[p release];
Person对象在这里无法正常释放,虽然表面看起来一个alloc对应一个release符合内存管理规则,但是实际在resetBlock方法实现中,Block内部对self进行了一次retain操作,导致循环引用无法释放
解决办法:
- 如果对象内部有一个Block属性,而在Block内部又访问了该对象,那么会造成循环引用,解决循环引用的办法是在对象的前面使用下划线下划线block来修饰,以避免Block对对象进行retain操作
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
@end
@implementation Person
- (void)dealloc
{
NSLog(@"Person dealloc");
Block_release(_myBlock);
[super dealloc];
}
@end
__block Person *p = [[Person alloc] init];
p.myBlock = ^{
NSLog(@"------%@", p);
};
p.myBlock();
[p release]; Person对象在这里可以正常被释放
NSLog(@"%ld",[p retainCount]); 还是1
p = nil; 回收指针,因为指针还在指向僵尸对象.
情况二:
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
- (void)resetBlock;
@end
@implementation Person
- (void)resetBlock
{
这里为了通用一点,可以使用__block typeof(self) p = self;
__block Person *p = self;
self.myBlock = ^{
NSLog(@"------%@", p);
};
}
- (void)dealloc
{
NSLog(@"Person dealloc");
Block_release(_myBlock);
[super dealloc];
}
@end
Person *p = [[Person alloc] init];
[p resetBlock];
[p release]; // Person对象在这里可以正常被释放
二.Block在ARC下的内存管理:
- 在ARC默认情况下,Block的内存存储在堆中,ARC会自动进行内存管理,程序员只需要避免循环引用即可
当Block变量出了作用域,Block的内存会被自动释放
void(^myBlock)() = ^{
NSLog(@"------");
};
myBlock();
- 在Block的内存存储在堆中时,如果在Block中引用了外面的对象,会对所引用的对象进行强引用,但是在Block被释放时会自动去掉对该对象的强引用,所以不会造成内存泄漏
Person *p = [[Person alloc] init];
void(^myBlock)() = ^{
NSLog(@"------%@", p);
};
myBlock();
Person对象在这里可以正常被释放
循环引用:
- 如果对象内部有一个Block属性,而在Block内部又访问了该对象,那么会造成循环引用
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
@end
@implementation Person
- (void)dealloc
{
NSLog(@"Person dealloc");
}
@end
Person *p = [[Person alloc] init];
p.myBlock = ^{
NSLog(@"------%@", p);
};
p.myBlock();
因为myBlock作为Person的属性,采用copy修饰符修饰(这样才能保证Block在堆里面,以免Block在栈中被系统释放),
所以Block会对Person对象进行一次强引用,导致循环引用无法释放
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
- (void)resetBlock;
@end
@implementation Person
- (void)resetBlock
{
self.myBlock = ^{
NSLog(@"------%@", self);
};
}
- (void)dealloc
{
NSLog(@"Person dealloc");
}
@end
Person *p = [[Person alloc] init];
[p resetBlock];
Person对象在这里无法正常释放,在resetBlock方法实现中,Block内部对self进行了一次强引用,
导致循环引用无法释放
情况一:
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
@end
@implementation Person
- (void)dealloc
{
NSLog(@"Person dealloc");
}
@end
Person *p = [[Person alloc] init];
__weak typeof(p) weakP = p;
p.myBlock = ^{
NSLog(@"------%@", weakP);
};
p.myBlock();
Person对象在这里可以正常被释放
情况二:
@interface Person : NSObject
@property (nonatomic, copy) void(^myBlock)();
- (void)resetBlock;
@end
@implementation Person
- (void)resetBlock
{
// 这里为了通用一点,可以使用__weak typeof(self) weakP = self;
__weak Person *weakP = self;
self.myBlock = ^{
NSLog(@"------%@", weakP);
};
}
- (void)dealloc
{
NSLog(@"Person dealloc");
}
@end
Person *p = [[Person alloc] init];
[p resetBlock];
Person对象在这里可以正常被释放
注: 关于下划线下划线block关键字在MRC和ARC下的不同
__block在MRC下有两个作用
1. 允许在Block中访问和修改局部变量
2. 禁止Block对所引用的对象进行隐式retain操作__block在ARC下只有一个作用
1. 允许在Block中访问和修改局部变量