iOS|iOS 正确创建使用数据源或代理方法。
简要
我们平时做SDK封装,可能会想用UITableView那样的设置数据源或代理的方式来做封装。
self.tableView.dataSource = self;
self.tableView.delegate = self;
这样做很好,我们可以自己封装一个。
需求点 昨天,我需要封装一个滚动号码球视图,像老虎机那种,它的子视图是由外部自定义的,我的想法是像tabelView自定义cell一样自定义子视图。
如何做 以我的SDK为例,我们先创建好数据源方法或代理方法
@protocol BTScrollBallDataSource
@optional
/// 要显示多少组号码
/// @param scrollBall 试图
- (NSInteger)numberOfSectionsInScrollBall:(BTScrollBallView *)scrollBall;
@end@interface BTScrollBallView : UIView
/// 数据源方法
@property (weak,nonatomic) id dataSource;
@end@implementation BTScrollBallView
- (instancetype)init{
self = [super init];
if (self) {
self.backgroundColor = UIColor.greenColor;
[self createLayers];
//在此处调用方法创建视图
}
return self;
}- (void)createLayers{
// 这里通过代理方法获取数据源个数
NSInteger sections = 0;
if ([self.dataSource respondsToSelector:@selector(numberOfSectionsInScrollBall:)]) {
sections = [self.dataSource numberOfSectionsInScrollBall:self];
}
}
@end
认真观察一下 到这里你可能会认为已经可以了,可以获取到数据了。
但其实这里有一个很大的问题:这里根本无法拿到数据源对象,这里的
self.dataSource
是为nil的。在控制器UIViewController中使用一下看看:
@interface UIViewController()
@property (strong,nonatomic) BTScrollBallView *scrollBall;
@end@implementation UIViewController- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.scrollBall];
}// MARK: - MKScrollBallDataSource
- (NSInteger)numberOfSectionsInScrollBall:(BTScrollBallView *)scrollBall{
return self.datas.count;
}- (BTScrollBallView *)scrollBall{
if (!_scrollBall) {
_scrollBall = [[BTScrollBallView alloc]init];
_scrollBall.dataSource = self;
}
return _scrollBall;
}
@end
【iOS|iOS 正确创建使用数据源或代理方法。】可以看到,我们调用完
_scrollBall = [[BTScrollBallView alloc]init];
之后才调用设置数据源_scrollBall.dataSource = self;
,这个时候BTScrollBallView视图中init方法想通过数据源获取数据怎么可能有值呢?那怎么办,难道要在初始化的时候把数据源
dataSource
或delegate
传进去吗?这限制太死了,非常不合理,我们看看更好的方式。正确的姿势 我们可以等视图已经完成添加到父视图之后再获取代理
delegate
或dataSource
,此时的视图已经初始化创建完成了。这时再去获取数据源代理就能获取成功。看看UIView的生命周期:
文章图片
UIView的生命周期
在UIView的生命周期有一条:
didMoveToSuperView
方法,这个方法就是视图被添加到父视图完成后走的方法。到这里就很明了了,我们在这个方法调用获取代理delgate或dataSource就没有问题了。
- (void)didMoveToSuperview{
[super didMoveToSuperview];
[self createLayers];
}- (void)createLayers{
NSInteger sections = 0;
if ([self.dataSource respondsToSelector:@selector(numberOfSectionsInScrollBall:)]) {
sections = [self.dataSource numberOfSectionsInScrollBall:self];
}
}
谢谢查阅!
详细代码:
BTScrollBallView
参考:
UIView生命周期
推荐阅读
- 2020-04-07vue中Axios的封装和API接口的管理
- django-前后端交互
- iOS中的Block
- 记录iOS生成分享图片的一些问题,根据UIView生成固定尺寸的分享图片
- IDEA|IDEA 创建工程
- 2019-08-29|2019-08-29 iOS13适配那点事
- Hacking|Hacking with iOS: SwiftUI Edition - SnowSeeker 项目(一)
- iOS面试题--基础
- 接口|axios接口报错-参数类型错误解决
- iOS|iOS 笔记之_时间戳 + DES 加密