本文属 iOS小经验系列:累积平时看起来简单,容易忽视的边边角角,各路大佬敬请回避。
设置UICollectionView的footer的时候,可能有新的小伙伴这样写:
问题代码:
- 头文件
#import <UIKit/UIKit.h>
@interface DownloadCollectionFooter : UICollectionReusableView
/** 标题 */
@property (nonatomic,strong) UIButton * footerBtn;
/** 内存 */
@property (nonatomic,strong) NSString * footerStr;
@end
- 实现文件
#import "DownloadCollectionFooter.h"
#import "Masonry.h"
@implementation DownloadCollectionFooter
- (instancetype)init
{
self = [super init];
if (self) {
//...
}
return self;
}
- (void)layoutSubviews{
[super layoutSubviews];
_footerBtn = [[UIButton alloc]init];
[_footerBtn setTitle:@"下载" forState:UIControlStateNormal];
_footerBtn.titleLabel.font = [UIFont systemFontOfSize:15];
[self addSubview:_footerBtn];
[_footerBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left).offset(25);
make.right.equalTo(self.mas_right).offset(-25);
make.top.equalTo(self.mas_top).offset(7);
make.height.mas_equalTo(@36);
}];
}
问题描述
导致死循环地执行layoutSubviews
代码。
问题原因
这是因为,通过Masonry设置约束之前的那个addSubview,会导致layoutSubviews
再次执行。那么,如果你在layoutSubviews
中设置addSubview,就导致死循环了。
解决方案
- 在初始化的时候设置Masonry。例如下面初始化的时候调用自定义的
initSubViews
,然后把原来写在layoutSubviews
的问题代码写在initSubViews
中去。
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self initSubViews];
}
return self;
}
如果你坚持想在layoutSubviews
写布局代码,仍然可以,也有个方案:
-
把addSubview写在初始化方法里面,或者写在子控件的懒加载里面,然后在layoutSubviews的方法里面再用Masonry设置布局约束。
-
或者,改用frame和bounds等绝对布局方式,addSubview之后,再用绝对布局,并不会 导致layoutSubviews再次执行,例如。
- (void)layoutSubviews{
[super layoutSubviews];
_titleLabel = [[UILabel alloc]init];
[self addSubview:_titleLabel];
_titleLabel.frame = CGRectMake(0, 7, SCREEN_WIDTH, 24);
_titleLabel.centerX = self.centerX;
_titleLabel.text = @"缓存";
//等等
}
实验结论
-
layoutSubviews
里面进行addSubview
操作,且通过 Masonry 设置布局,就 会 导致死循环地执行layoutSubviews
。 -
layoutSubviews
里面进行addSubview
操作,且通过 绝对布局 设置布局,并不会 导致死循环地执行layoutSubviews
。 -
layoutSubviews
里面 不 进行addSubview
操作,且通过 Masonry 设置布局,并不会 导致死循环地执行layoutSubviews
。
网友评论