美文网首页iOS新知识iOS学习
iOS 正确创建使用数据源或代理方法。

iOS 正确创建使用数据源或代理方法。

作者: Hanfank | 来源:发表于2020-05-30 00:25 被阅读0次

    简要

    我们平时做SDK封装,可能会想用UITableView那样的设置数据源或代理的方式来做封装。

    self.tableView.dataSource = self;
    self.tableView.delegate = self;
    

    这样做很好,我们可以自己封装一个。

    需求点

    昨天,我需要封装一个滚动号码球视图,像老虎机那种,它的子视图是由外部自定义的,我的想法是像tabelView自定义cell一样自定义子视图。

    如何做

    以我的SDK为例,我们先创建好数据源方法或代理方法

    @protocol BTScrollBallDataSource <NSObject>
    @optional
    /// 要显示多少组号码
    /// @param scrollBall 试图
    - (NSInteger)numberOfSectionsInScrollBall:(BTScrollBallView *)scrollBall;
    @end
    
    
    
    @interface BTScrollBallView : UIView
    /// 数据源方法
    @property (weak,nonatomic) id<BTScrollBallDataSource> 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的生命周期:

    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 正确创建使用数据源或代理方法。

        本文链接:https://www.haomeiwen.com/subject/yayqzhtx.html