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

可以看到,我们调用完_scrollBall = [[BTScrollBallView alloc]init]; 之后才调用设置数据源_scrollBall.dataSource = self;,这个时候BTScrollBallView视图中init方法想通过数据源获取数据怎么可能有值呢?

那怎么办,难道要在初始化的时候把数据源dataSourcedelegate传进去吗?这限制太死了,非常不合理,我们看看更好的方式。

正确的姿势

我们可以等视图已经完成添加到父视图之后再获取代理delegatedataSource,此时的视图已经初始化创建完成了。这时再去获取数据源代理就能获取成功。
看看UIView的生命周期:

iOS 正确创建使用数据源或代理方法。_第1张图片
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生命周期

你可能感兴趣的:(iOS 正确创建使用数据源或代理方法。)