美文网首页
reloadData 结束回调

reloadData 结束回调

作者: youlianchun | 来源:发表于2018-02-12 08:17 被阅读0次

    在使用UITableview或者UICollectionView时候或许会碰到这种情况:在reloadData执行完成时候进行某些操作,但是apple提供的方法并不支持,查阅互联网资料大概得三种种方法
    一:采用dispatch_anync();二:采用UIView的animation;三:采用dispatch_after()。
    经过测试,这三种方方法在reload过程中存在耗时操作情况都没办法做的很准确,甚至先于reload结束。
    这边介绍一种新的方式,原理是在reload发起之前监听content
    size的设置,并且给个很短超时时间,一旦超时表示reload完成,执行回调。具体如下:

    #import <UIKit/UITableView.h>
    #import <UIKit/UICollectionView.h>
    
    //前一次 -[ reloadData:] 结束前再次 -[ reloadData:] 将抛弃前次结果
    //注:-[ reloadData:]不会产生循环应用
    
    @interface UITableView (reload)
    -(void)reloadData:(void(^)(void))complete;
    @end
    
    @interface UICollectionView (reload)
    -(void)reloadData:(void(^)(void))complete;
    @end
    
    #import "ReloadedData.h"
    #import <objc/runtime.h>
    
    
    #pragma mark - objc/runtime
    @interface _WeakObject : NSObject
    @property (nonatomic, weak)id weak;
    @end
    @implementation _WeakObject
    @end
    
    static id get_attribute_strong(id object, const void * key)
    {
        return objc_getAssociatedObject(object, key);
    }
    
    static void set_attribute_strong(id object, const void * key, id value)
    {
        objc_setAssociatedObject(object, key, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    static id get_attribute_weak(id object, const void * key)
    {
        _WeakObject *weak = get_attribute_strong(object, key);
        return weak.weak;
    }
    
    static void set_attribute_weak(id object, const void * key, id value)
    {
        _WeakObject *weak;
        if (value)
        {
            weak = get_attribute_strong(object, key);
            if (!weak) {
                weak = [_WeakObject new];
            }
            weak.weak = value;
        }
        set_attribute_strong(object, key, weak);
    }
    
    
    #pragma mark - _ReloadedData
    @interface _ReloadedData : NSObject
    @property (nonatomic, strong) UIScrollView *view;
    @property (nonatomic, copy) void(^callback)(void);
    @end
    
    @implementation _ReloadedData
    
    static _ReloadedData* build_reloadedData(UIScrollView *view, void(^complete)(void))
    {
        __block _ReloadedData *reloadedData = [[_ReloadedData alloc] init];
        reloadedData.view = view;
        reloadedData.callback = ^{
            reloadedData = nil;
            complete();
        };
        return reloadedData;
    }
    
    -(void)setView:(UIScrollView *)view
    {
        static NSString * const kContentSize = @"contentSize";
        [_view removeObserver:self forKeyPath:kContentSize];
        _view = view;
        [_view addObserver:self forKeyPath:kContentSize options:NSKeyValueObservingOptionNew context:nil];
    }
    
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
    {
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        [self performSelector:@selector(onTimeOut) withObject:nil afterDelay:0.05];
    }
    
    -(void)onTimeOut
    {
        void(^callback)(void) = self.callback;
        [self scrap];
        callback();
    }
    
    -(void)scrap
    {
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        self.callback = nil;
        self.view = nil;
    }
    
    -(void)dealloc
    {
        [self scrap];
    }
    
    @end
    
    
    #pragma mark - UITableView UICollectionView
    @interface UIScrollView ()
    - (id<UITableViewDataSource>)dataSource;
    - (void)reloadData;
    @end
    
    @implementation UIScrollView (TableViewOrCollectionView)
    
    -(_ReloadedData *)rdObserver
    {
        return get_attribute_weak(self, @selector(rdObserver));
    }
    
    -(void)setRdObserver:(_ReloadedData *)rdObserver
    {
        set_attribute_weak(self, @selector(rdObserver), rdObserver);
    }
    
    -(void)reloadData:(void(^)(void))complete
    {
        if (complete && self.delegate && self.dataSource)
        {
            [self.rdObserver scrap];
            self.rdObserver = build_reloadedData(self, complete);
        }
        [self reloadData];
    }
    
    @end
    
    

    注意:reloadData方法仅仅是渲染当前显示部分的内容,内容很多的情况貌似并不能得到整个的contentSize。这边的回调也在这个条件内。
    回调不需要处理循环引用,有兴趣看一下代码。
    欢迎反馈意见和bug

    相关文章

      网友评论

          本文标题:reloadData 结束回调

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