对block自身内存的管理
对于block,有两个内存管理方法:Block_copy
, Block_release
;Block_copy
与copy
等效,Block_release
与release
等效;
不管是对block进行retian
,copy
,release
,block
的引用计数都不会增加,始终为1;
-
NSGlobalBlock
:使用retain
,copy
,release
都无效,block依旧存在全局区,且没有释放, 使用copy
和retian
只是返回block的指针; -
NSStackBlock
:使用retain
,release
操作无效;栈区block会在方法返回后将block空间回收; 使用copy
将栈区block复制到堆区,可以长久保留block的空间,以供后面的程序使用; -
NSMallocBlock
:支持retian
,release
,虽然block的引用计数始终为1,但内存中还是会对引用进行管理,使用retain
引用+1,release
引用-1; 对于NSMallocBlock
使用copy
之后不会产生新的block,只是增加了一次引用,类似于使用retian
;
对引用变量的内存管理
如果该block为NSMallocBlock
或者被copy成NSMallocBlock
类型则其引用的外界变量的引用计数会被+1,当block释放时外界变量的引用计数-1,而block为NSStackBlock
或NSGlobalBlock
类型时外界变量的引用计数不会变,例子NSMallocBlock
:
- (void)testBlock {
NSObject *obj = [[NSObject alloc] init];
NSLog(@"obj.retainCount = %ld", obj.retainCount);
void(^normalBlock)(int, int) = ^(int a, int b) {
NSLog(@"normalBlock = %d %@", a + b, obj);
};
NSLog(@"obj.retainCount = %ld", obj.retainCount);
NSLog(@"normalBlock %@", normalBlock);
void(^normalCopyBlock)(int, int) = [normalBlock copy];
NSLog(@"normalCopyBlock %@", normalCopyBlock);
NSLog(@"obj.retainCount = %ld", obj.retainCount);
}
输出:
2020-04-20 16:03:56.412850+0800 obj.retainCount = 1
2020-04-20 16:03:56.414244+0800 obj.retainCount = 1
2020-04-20 16:03:56.414685+0800 normalBlock <__NSStackBlock__: 0x7ffeefbff538>
2020-04-20 16:03:56.414798+0800 normalCopyBlock <__NSMallocBlock__: 0x100625400>
2020-04-20 16:03:56.414985+0800 obj.retainCount = 2
例子NSGlobalBlock
:
NSObject *obj = nil;
- (void)testBlock {
obj = [[NSObject alloc] init];
NSLog(@"obj.retainCount = %ld", obj.retainCount);
void(^normalBlock)(int, int) = ^(int a, int b) {
NSLog(@"normalBlock = %d %@", a + b, obj);
};
NSLog(@"obj.retainCount = %ld", obj.retainCount);
NSLog(@"normalBlock %@", normalBlock);
void(^normalCopyBlock)(int, int) = [normalBlock copy];
NSLog(@"normalCopyBlock %@", normalCopyBlock);
NSLog(@"obj.retainCount = %ld", obj.retainCount);
}
输出:
0-04-20 16:14:01.728789+0800 obj.retainCount = 1
2020-04-20 16:14:01.729195+0800 obj.retainCount = 1
2020-04-20 16:14:01.729499+0800 normalBlock <__NSGlobalBlock__: 0x100002030>
2020-04-20 16:14:01.729582+0800 normalCopyBlock <__NSGlobalBlock__: 0x100002030>
2020-04-20 16:14:01.729636+0800 obj.retainCount = 1
循环引用
-
__block
在MRC中使用,NSMallocBlock
类型的block不会对__block
修饰的的变量引用计数+1,从而消除循环引用,并且可以让该变量在block内被赋值;在ARC中使用__block
只是可以让该变量在block内被赋值。 -
__weak
在ARC中使用,作用和__block一样,从而消除循环引用;在非ARC中不可以使用__weak
;
MRC下例子:
@property (nonatomic, copy, readwrite) void (^copyBlock)(void);
- (void)testBlock {
NSObject *obj = [[NSObject alloc] init];
NSLog(@"obj.retainCount = %ld", obj.retainCount);
self.copyBlock = ^() {
NSLog(@"copyBlock = %@", obj);
};
NSLog(@"obj.retainCount = %ld", obj.retainCount);
NSLog(@"normalBlock %@", self.copyBlock);
}
输出:
2020-04-20 16:23:12.712386+0800 obj.retainCount = 1
2020-04-20 16:23:12.713195+0800 obj.retainCount = 2
2020-04-20 16:23:12.713557+0800 normalBlock <__NSMallocBlock__: 0x100707d40>
MRC下例子:
@property (nonatomic, copy, readwrite) void (^copyBlock)(void);
- (void)testBlock {
__block NSObject *obj = [[NSObject alloc] init];
NSLog(@"obj.retainCount = %ld", obj.retainCount);
self.copyBlock = ^() {
NSLog(@"copyBlock = %@", obj);
};
NSLog(@"obj.retainCount = %ld", obj.retainCount);
NSLog(@"normalBlock %@", self.copyBlock);
}
输出:
2020-04-20 16:28:59.888767+0800 obj.retainCount = 1
2020-04-20 16:28:59.889190+0800 obj.retainCount = 1
2020-04-20 16:28:59.889454+0800 normalBlock <__NSMallocBlock__: 0x1006518e0>
网友评论