接手过不少项目很多block要么乱用,要么就烂用。
block 产生循环引用终归都是相互持有。相信大多人都能明白,但用着用着就糊涂了。不知道是不是会产生。
下面写了个测试代码希望能帮到有需要的人。代码不多,然望看完。
有圈就是环,没圈就不成环,不释放不一定就是环所至,可能是生命周期。
//
// AFBlockDesigned.h
// AFBlockCylce
//
// Created by fengsh on 2019/1/28.
// Copyright © 2019年 fengsh. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void(^PersistentBlock) (NSString *msg);
NS_ASSUME_NONNULL_BEGIN
@interface AFBlockDesigned : NSObject
@property (nonatomic, copy) PersistentBlock strongBlock;
///非单例
+ (instancetype)manager;
///单例
+ (instancetype)share;
///会产生循环引用的block
- (void)reqeustForPersistentBlock:(PersistentBlock)block;
///使劲用,不产生,我就不产生。
- (void)reqeustForWeakBlock:(PersistentBlock)block;
@end
NS_ASSUME_NONNULL_END
//
// AFBlockDesigned.m
// AFBlockCylce
//
// Created by fengsh on 2019/1/28.
// Copyright © 2019年 fengsh. All rights reserved.
//
#import "AFBlockDesigned.h"
@implementation AFBlockDesigned
- (void)dealloc
{
NSLog(@"AFBlockDesigned Free.");
}
+ (instancetype)manager
{
return [[[self class] alloc]init];
}
+ (instancetype)share
{
static AFBlockDesigned *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[AFBlockDesigned alloc]init];
});
return instance;
}
///会产生循环引用的block
- (void)reqeustForPersistentBlock:(PersistentBlock)block
{
///全局 hold它
self.strongBlock = block;
dispatch_queue_t queue = dispatch_queue_create("com.fsh.pb", 0);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];
block(@"【reqeustForPersistentBlock:】");
});
}
///使劲用,不产生,我就不产生。
- (void)reqeustForWeakBlock:(PersistentBlock)block
{
dispatch_queue_t queue = dispatch_queue_create("com.fsh.pb", 0);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];
block(@"【reqeustForWeakBlock:】");
});
}
@end
下面上测试代码:
//
// GreenViewController.m
// AFBlockCylce
//
// Created by fengsh on 2019/1/28.
// Copyright © 2019年 fengsh. All rights reserved.
//
#import "GreenViewController.h"
#import "AFBlockDesigned.h"
@interface GreenViewController ()
@property (nonatomic, strong) AFBlockDesigned *manager;
@property (nonatomic, strong) NSMutableArray *all;
@property (nonatomic, strong) AFBlockDesigned *shareGloble;
@end
@implementation GreenViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.all = [NSMutableArray array];
// [self testCycleRef]; ///产生循环引用
// [self testWeakFree]; ///局部持有block, 没有循环引用
// [self testWeakRef]; ///使用弱引用,没有循环引用
// [self testSingle]; ///单例情况,不持有,只是引用计数释放的生命周期而已,并非循环引用.
// [self testSingleLocalBlock];///单例情况,不持有,生命周期到了就free.并非循环引用.
// [self testSingleGloble]; ///产生循环引用
[self testSingleGlobleLocalBlock]; ///不产生循环引用
}
/*
会产生循环引用
self(GreenViewController)---------->持有self.manager()----------->持有block
^ |
|___________________________持有____________________________|
*/
- (void)testCycleRef
{
self.manager = [AFBlockDesigned manager];
PersistentBlock block = ^(NSString * msg) {
[self.all addObject:msg];
NSLog(@"%@ ,self.manager,self,block相互持有,形成强环了。",msg);
};
NSLog(@"self地址:%p , self.manager地址:%p, block地址:%p",&self,&_manager,&block);
NSLog(@"self地址:%p , self.manager地址:%p, block地址:%p",self,_manager,block);
[self.manager reqeustForPersistentBlock:block];
// [self.manager reqeustForPersistentBlock:^(NSString * msg) {
// [self.all addObject:msg];
// NSLog(@"%@ ,self.manager,self,block相互持有,形成强环了。",msg);
// }];
NSLog(@"%s ---end---",__FUNCTION__);
}
/*
不会产生循环引用
self(GreenViewController)-----持有----->self.manager()-----不持有----->block
^ |
|___________________________持有____________________________|
*/
- (void)testWeakFree
{
self.manager = [AFBlockDesigned manager];
[self.manager reqeustForWeakBlock:^(NSString * msg) {
[self.all addObject:msg];
NSLog(@"%@ ,block只作入参,不持有block",msg);
}];
NSLog(@"%s ---end---",__FUNCTION__);
}
/*
不会产生循环引用
self(GreenViewController)----持有------>self.manager()-----持有----->block
^ |
|.......................weak持有............................|
*/
- (void)testWeakRef
{
self.manager = [AFBlockDesigned manager];
__weak typeof(self) ws = self;
[self.manager reqeustForPersistentBlock:^(NSString * msg) {
__strong typeof(self) ss = ws;
[ss.all addObject:msg];
NSLog(@"%@ 使用了__weak进行修饰,打破强引用!",msg);
}];
NSLog(@"%s ---end---",__FUNCTION__);
}
/*
单例模式:不会产生循环引用,但由于引用计数不为0,故没有释放,并不是循环引用
self(GreenViewController)-----不持有----->单例-----------持有---------->block
^ |
|___________________________持有_________________________________|
*/
- (void)testSingle
{
[[AFBlockDesigned share]reqeustForPersistentBlock:^(NSString *msg) {
[self.all addObject:msg];
NSLog(@"单例 %@,并不持有,因此没成环!,但为啥不释放啊,因为这是个全局单例,在这里引用计数被+1了.",msg);
// [AFBlockDesigned share].strongBlock = nil;加这一句就是释放block从而使self的引用计数-1
}];
NSLog(@"%s ---end---",__FUNCTION__);
}
/*
单例模式:不会产生循环引用,但由于引用计数不为0,故没有释放,并不是循环引用
self(GreenViewController)-----不持有----->单例-----------不持有---------->block
^ |
|____________________________持有_________________________________|
*/
- (void)testSingleLocalBlock
{
[[AFBlockDesigned share]reqeustForWeakBlock:^(NSString *msg) {
[self.all addObject:msg];
NSLog(@"%@ self不持有,单例不持有block,没有形成环,函数执行完成后block也随之被free.所以对self的引用计数也减1",msg);
}];
NSLog(@"%s ---end---",__FUNCTION__);
}
/*
单例模式:产生循环引用
self(GreenViewController)-----持有----->单例-----------持有---------->block
^ |
|____________________________持有_________________________________|
*/
- (void)testSingleGloble
{
self.shareGloble = [AFBlockDesigned share];
[self.shareGloble reqeustForPersistentBlock:^(NSString *msg) {
[self.all addObject:msg];
NSLog(@"%@ 单例并且持有了! 会有循环引用问题",msg);
}];
NSLog(@"%s ---end---",__FUNCTION__);
}
/*
单例模式:不会产生循环引用
self(GreenViewController)-----持有----->单例----------不持有--------->block
^ |
|____________________________持有_________________________________|
*/
- (void)testSingleGlobleLocalBlock
{
self.shareGloble = [AFBlockDesigned share];
[self.shareGloble reqeustForWeakBlock:^(NSString *msg) {
[self.all addObject:msg];
NSLog(@"%@ 持有单例,但不持有block",msg);
}];
NSLog(@"%s ---end---",__FUNCTION__);
}
- (void)dealloc
{
NSLog(@"GreenViewController Free.");
}
@end
最后上两个clang 转C代码,有兴趣的可以看下转C后的结构,从底往上看。都是struct不麻烦的。
方式一:clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk AFBlockDesigned.m
注意这里还有些可能存在依赖问题,要针对性加参数处理。
方式二:
xcrun -sdk iphonesimulator clang -rewrite-objc -fobjc-arc -fblocks -fobjc-runtime=ios-12.1 GreenViewController.m
DEMO:上传完成再来修改地址。CSDN强行设置5分太恶心了。要吐。不能设0么?