在使用UITableview或者UICollectionView時候或許會碰到這種情況:在reloadData執(zhí)行完成時候進(jìn)行某些操作,但是apple提供的方法并不支持,查閱互聯(lián)網(wǎng)資料大概得三種種方法
一:采用dispatch_anync();二:采用UIView的animation;三:采用dispatch_after()。
經(jīng)過測試,這三種方方法在reload過程中存在耗時操作情況都沒辦法做的很準(zhǔn)確,甚至先于reload結(jié)束。
這邊介紹一種新的方式,原理是在reload發(fā)起之前監(jiān)聽content
size的設(shè)置,并且給個很短超時時間,一旦超時表示reload完成,執(zhí)行回調(diào)。具體如下:
#import <UIKit/UITableView.h>
#import <UIKit/UICollectionView.h>
//前一次 -[ reloadData:] 結(jié)束前再次 -[ reloadData:] 將拋棄前次結(jié)果
//注:-[ reloadData:]不會產(chǎn)生循環(huán)應(yīng)用
@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方法僅僅是渲染當(dāng)前顯示部分的內(nèi)容,內(nèi)容很多的情況貌似并不能得到整個的contentSize。這邊的回調(diào)也在這個條件內(nèi)。
回調(diào)不需要處理循環(huán)引用,有興趣看一下代碼。
歡迎反饋意見和bug