iOS小记--block的循环引用问题以及block何时需要/不需要使用[weak self]

其实这个问题不需要说太多了,只需要抓住会造成循环引用的本质原因就可以了.

如果block没有直接或者间接被self存储,就不会产生循环引用。就不需要用weak self####

引发循环引用,是因为当前self在强引用着block,而block又引用着self,这样就造成了循环引用。而需不需要使用[weak self]就是由循环引用来决定,如果造成了循环引用,就必须使用[weak self]来打破循环.

1.直接强引用####

来分析一个自己设计的block模块:
// 这种情况不必要弱引用 [self oneBlockSucess:^{ [self doSomething]; }]; //这种情况就有必需用weakself来打破引用环 self.secondBlock = ^{ [self doSomething]; };
self.secondBlock说明当前self持有了secondBlock这个block属性,block属性是由copy来声明的,@property(nonatomic, copy)BtnSecondBlockBlock secondBlock;属于对象self的强引用属性.
所以如果在block回调内想拿到self去做一些业务处理时,如果直接使用self,就会造成block持有了self,两者互相持有,造成循环引用.打破这个环,就要使用如typeof(self) __weak weakSelf = self;的weakSelf方式;

2.间接强引用####

再来分析一个自己设计的block模块:

这是一个持有block的view: XXSubmitBottomView

typedef void(^BtnPressedBlock)(UIButton *btn);

@interface XXSubmitBottomView : UIView

@property(strong,nonatomic)UILabel *allPriceLab;
@property(strong,nonatomic)UIButton *submittBtn;
@property(nonatomic, weak)XXConfirmOrderController *currentVc;
@property(nonatomic, weak)XXConfimOrderModel *model;

@property(nonatomic, copy)BtnPressedBlock block;
-(void)submittBtnPressed:(BtnPressedBlock)block;

@end

这是一个持有bottomView属性的控制器: XXConfirmOrderController


@interface XXConfirmOrderController ()

@property(nonatomic, strong) XXConfimOrderTableView *tableView;
@property(nonatomic, strong) XXSubmitBottomView *bottomView;
@property(nonatomic, strong) XXConfimOrderModel *confimModel;

@end

@implementation XXConfirmOrderController

-(void)viewDidLoad{
    [super viewDidLoad];
    self.title = @"确认下单";
    self.view.backgroundColor = DDCJ_Gray_Color;
    
    //UI
    [self.view addSubview:self.tableView];
    [self.view addSubview:self.bottomView];
    
    //Data
    [self loadData];
}

下面是self.bottomView的懒加载以及block的回调处理

-(XXSubmitBottomView *)bottomView{
    if (!_bottomView) {
        _bottomView = [[XXSubmitBottomView alloc] initWithFrame:CGRectMake(0, self.view.height - 50, Width, 50)];
        _bottomView.currentVc = self;
        
        
#warning self.bottomView.block  self间接持有了BtnPressedBlock 必须使用weak!
        
        WEAKSELF  //ps: weakSelf的宏定义#define WEAKSELF typeof(self) __weak weakSelf = self;
       
        
        [_bottomView submittBtnPressed:^(UIButton *btn) {
            
            NSLog(@"do提交订单");
            
             MBProgressHUD *hud = [MBProgressHUD showMessage:@"加载中..." toView:weakSelf.view];
            
            NSMutableDictionary *dynamic = [NSMutableDictionary dictionary];
            [dynamic setValue:weakSelf.confimModel.orderRemark forKey:@"orderRemark"];
            if (weakSelf.agreementId) {
                [dynamic setValue:weakSelf.agreementId forKey:@"agreementId"];
            }
            if (weakSelf.isShoppingCartEnter) {
                [dynamic setValue:@"0" forKey:@"orderOrigin"];
            }else{
                [dynamic setValue:@"1" forKey:@"orderOrigin"];
            }
                        
            [[APIClientFactory sharedManager] requestConfimOrderWithDynamicParams:dynamic success:^(NSMutableArray *dataArray) {
                
                [hud hideAnimated:YES];                
                [weakSelf handlePushControllerWithModelList:dataArray];
                
            } failure:^(NSError *error) {
                [hud hideAnimated:YES];
                [MBProgressHUD showError:error.userInfo[@"message"]];
            }];
        }];
    }
    
    return _bottomView;
}

这里的warning信息其实已经写的很清楚了,#warning self.bottomView.block self间接持有了BtnPressedBlock 必须使用weak!

此处的控制器self并没有直接持有block属性,但是却强引用了bottomView,bottomView强引用了block属性,这就造成了间接循环引用. block回调内必须使用[weak self]来打破这个循环,否则就会导致这个控制器self永远都不会被释放掉产生常驻内存。如果self.bottomViewbottomView.block有一环不是强引用,就不会产生循环引用问题,因为不会形成一个引用环. 如果一个应用程序里面你有很多循环引用,那么内存占用就会比较大,并且由于一些特殊操作,会产生一个控制器的N个对象实例常驻内存无法释放,造成大量的系统内存泄漏,这当然是谁都不想看到的结果.#####

打破这个环,就要使用如typeof(self) __weak weakSelf = self;的weakSelf方式;

自己设计的block模块都可以在合适时机进行打断。打断的方式就是使用self的弱引用即可.

如果是对系统类加扩展方法导致的循环引用,那么需要找得到合适的时机打断,也是没问题的。
另外有个简单的方法可以绕过这个问题,如果self引用了一个block,block又需要调用self,可以

把self通过参数回传给block,这样就不会产生循环引用了。
block回传的self可以声明成id类型,这样使用的时候可以在入参声明具体self类型,避免显式类型转换,方便开发。

typedef void (^Block) (id selfRef);
Block block = ^(XXX *selfRef){
};

这是一种比较巧妙一点的处理方式.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容