MYTableViewManager、TFTableViewDataSource淺析朗和;

https://github.com/melvin7/MYTableViewManager

https://github.com/TimeFaceCoder/TFTableViewDataSource

TFTableViewDataSource 包含以下幾個(gè)基本類

  • TFTableViewDataSourceConfig : 用于配置列表數(shù)據(jù)獲取接口错沽,處理函數(shù),分頁(yè)記錄數(shù)等
  • TFTableViewDataSource : TableView數(shù)據(jù)源處理類例隆,通過(guò)繼承TFTableViewDataSource 可以重載下拉刷新甥捺,列表展示等方法來(lái)實(shí)現(xiàn)自定義
  • TFTableViewDataManager 列表數(shù)據(jù)處理工具,所有的列表數(shù)據(jù)處理都需要繼承TFTableViewDataManager來(lái)處理
  • TFTableViewItem 單行列表數(shù)據(jù)源與事件處理類镀层,所有的列表數(shù)據(jù)源都需要繼承TFTableViewItem來(lái)處理
  • TFTableViewItemCell 單行列表UI镰禾,所有的列表UI都需要繼承TFTableViewItemCell來(lái)處理

1皿曲、回頭看看,這框架還是很模糊拔庹臁屋休;

DCSwitchTableViewItem

處理item點(diǎn)擊事件有,onViewClickHandler备韧,selectionHandler等劫樟;

2、DCManegerDataManeger织堂,

TFTableViewDataManager初始化時(shí)initWithDataSource叠艳,會(huì)設(shè)置下_cellViewClickHandler;會(huì)先處理代理VC的事件

if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) 

3易阳、tableView Cell 響應(yīng)事件附较;

DCManagerTableViewItem setSelectionHandler:)

tableView:didSelectRowAtIndexPath:

調(diào)用 MYTableViewItem 的 selectionHandler

TFTableViewItem : MYTableViewItem

單行列表數(shù)據(jù)源和事件處理類; 所有的列表數(shù)據(jù)源都要繼承TFTableViewItem來(lái)處理;

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }
    __weak typeof(self) weakself = self;
    self.selectionHandler = ^(id item){
        if (weakself.onViewClickHandler) {
            weakself.onViewClickHandler(item, -1);
        }
    };
    return self;
}

在TFTableViewItem的init方法中初始化了父類MYTableViewItem的selectionHandler潦俺;
里面調(diào)用自己的屬性onViewClickHandler拒课;而其初始化在temWithModel:clickHandler:中;

@property (nonatomic ,copy) void (^onViewClickHandler)(TFTableViewItem *item,NSInteger actionType);

事示?早像??selectionHandler肖爵、onViewClickHandler在哪里調(diào)用的卢鹦;

TFTableViewItemCell : MYTableViewCell

單行列表UI,所有的列表UI都繼承自TFTableViewItemCell來(lái)處理遏匆;

沒有code法挨, 主要看其父類MYTableViewCell : ASCellNode

- (instancetype)initWithTableViewItem:(MYTableViewItem *)tableViewItem {
    self = [super init];
    if(self) {
        self.tableViewItem = tableViewItem;
        
        // hairline cell separator
        if (self.tableViewItem.separatorStyle != UITableViewCellSeparatorStyleNone) {
            _dividerNode = [[ASDisplayNode alloc] init];
            _dividerNode.backgroundColor = self.tableViewItem.dividerColor;
            [self addSubnode:_dividerNode];
        }
        [self initCell];
    }
    return self;
}

MYTableViewCell繼承自ASCellNode谁榜;整體基于ASTableView實(shí)現(xiàn)幅聘;
在initWithTableViewItem方法中設(shè)置列表數(shù)據(jù)源self.tableViewItem;調(diào)用initCell方法窃植;

所以在我們自定義的cell中帝蒿,在initCell中初始化UI;

ASDisplayKit中l(wèi)ayout相當(dāng)于layoutSubviews巷怜;重新布局葛超;分為自動(dòng)布局、手動(dòng)布局延塑;

TFTableViewDataManager : NSObject<TFTableViewDataManagerProtocol>

列表數(shù)據(jù)處理工具绣张,所有的列表數(shù)據(jù)處理都需要繼承TFTableViewDataManager來(lái)處理;

管理類关带,管理cell數(shù)據(jù)源item侥涵,cell的UI-cell;

@interface TFTableViewDataManager : NSObject<TFTableViewDataManagerProtocol>

@property (nonatomic ,weak) TFTableViewDataSource *tableViewDataSource;

/**
 *  列表內(nèi)點(diǎn)擊事件 block
 */
@property (nonatomic ,copy) CellViewClickHandler   cellViewClickHandler;

/**
 *  列表刪除事件 block
 */
@property (nonatomic ,copy) DeletionHandlerWithCompletion deleteHanlder;

/**
 *  當(dāng)前cell的索引indexPath
 */
@property (nonatomic ,strong) NSIndexPath *currentIndexPath;

/**
 *  對(duì)應(yīng)的listType,綁定url
 */
@property (nonatomic ,assign) NSInteger listType;

/**
 *  清除上面的block
 */
- (void)clearCompletionBlock;

@end

查看TFTableViewDataManager的實(shí)現(xiàn)芜飘;發(fā)現(xiàn)其initWithDataSource在dataSource中調(diào)用务豺;
manager對(duì)dataSource弱引用;dataSource中對(duì)manager強(qiáng)引用嗦明;避免循環(huán)引用笼沥;

@implementation TFTableViewDataManager

- (instancetype)initWithDataSource:(TFTableViewDataSource *)tableViewDataSource
                          listType:(NSInteger)listType {
    self = [super init];
    if (!self) {
        return nil;
    }
    _tableViewDataSource = tableViewDataSource;
    _listType = listType;
    __weak __typeof(self)weakSelf = self;
    _cellViewClickHandler = ^ (TFTableViewItem *item ,NSInteger actionType) {
        __typeof(&*weakSelf) strongSelf = weakSelf;
        strongSelf.currentIndexPath = item.indexPath;
        [item deselectRowAnimated:YES];
        if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) {
            [strongSelf.tableViewDataSource.delegate actionOnView:item actionType:actionType];
        }
        [strongSelf cellViewClickHandler:item actionType:actionType];
    };
    
    _deleteHanlder = ^(TFTableViewItem *item ,Completion completion) {
        __typeof(&*weakSelf) strongSelf = weakSelf;
        [strongSelf deleteHanlder:item completion:completion];
    };
    return self;
}

/**
 *  顯示列表數(shù)據(jù)
 *
 *  @param result          數(shù)據(jù)字典
 *  @param completionBlock 回調(diào)block
 */
- (void)reloadView:(NSDictionary *)result block:(TableViewReloadCompletionBlock)completionBlock {
    
}
/**
 *  列表內(nèi)View事件處理
 *
 *  @param item
 *  @param actionType
 */
- (void)cellViewClickHandler:(TFTableViewItem *)item actionType:(NSInteger)actionType {
    self.currentIndexPath = item.indexPath;
}
/**
 *  列表刪除事件處理
 *
 *  @param item
 */
- (void)deleteHanlder:(TFTableViewItem *)item completion:(void (^)(void))completion {
    self.currentIndexPath = item.indexPath;
}

/**
 *  刷新指定Cell
 *
 *  @param actionType
 *  @param dataId
 */
- (void)refreshCell:(NSInteger)actionType identifier:(NSString *)identifier {
    
}


- (void)clearCompletionBlock {
    self.cellViewClickHandler = nil;
    self.deleteHanlder        = nil;
}

@end

在)initWithDataSource:listType:中初始化了cellViewClickHandler、deleteHanlder娶牌;
其中cellViewClickHandler中會(huì)回調(diào)datasource的代理類(通常為TFTableViewController的子類)奔浅;這樣就將cell的事件回傳到ViewController了;

_cellViewClickHandler = ^ (TFTableViewItem *item ,NSInteger actionType) {
    __typeof(&*weakSelf) strongSelf = weakSelf;
    strongSelf.currentIndexPath = item.indexPath;
    [item deselectRowAnimated:YES];
    if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) {
        [strongSelf.tableViewDataSource.delegate actionOnView:item actionType:actionType];
    }
    [strongSelf cellViewClickHandler:item actionType:actionType];
};

看看協(xié)議接口TFTableViewDataManagerProtocol有哪些東西诗良;

ifndef TFTableViewDataManagerProtocol_h
#define TFTableViewDataManagerProtocol_h

#import "TFTableViewDataSource.h"
#import <TFNetwork/TFNetwork.h>

@class TFTableViewItem;
@class MYTableViewSection;
typedef void (^Completion)(void);
typedef void (^CellViewClickHandler)(__kindof TFTableViewItem *item ,NSInteger actionType);
typedef void (^DeletionHandlerWithCompletion)(__kindof TFTableViewItem *item, void (^)(void));
typedef void (^TableViewReloadCompletionBlock)(BOOL finished,id object,NSError *error, NSArray <MYTableViewSection *> *sections);


@protocol TFTableViewDataManagerProtocol <NSObject>

@required
/**
 *  列表業(yè)務(wù)類初始化
 *
 *  @param tableViewDataSource 列表數(shù)據(jù)源
 *  @param listType            列表類型
 *
 *  @return TFTableDataSourceManager
 */
- (instancetype)initWithDataSource:(TFTableViewDataSource *)tableViewDataSource
                          listType:(NSInteger)listType;

/**
 *  顯示列表數(shù)據(jù)
 *
 *  @param result          數(shù)據(jù)字典
 *  @param completionBlock 回調(diào)block
 */
- (void)reloadView:(NSDictionary *)result block:(TableViewReloadCompletionBlock)completionBlock;
/**
 *  列表內(nèi)View事件處理
 *
 *  @param item
 *  @param actionType
 */
- (void)cellViewClickHandler:(TFTableViewItem *)item actionType:(NSInteger)actionType;
/**
 *  列表刪除事件處理
 *
 *  @param item
 */
- (void)deleteHanlder:(TFTableViewItem *)item completion:(void (^)(void))completion;

/**
 *  刷新指定Cell
 *
 *  @param actionType
 *  @param dataId
 */
- (void)refreshCell:(NSInteger)actionType identifier:(NSString *)identifier;

@end

#endif

TFTableViewDataSource : NSObject

TabelView數(shù)據(jù)源處理類乘凸,通過(guò)繼承TFTableViewDataSource可以重載下拉刷新、列表展示等方法來(lái)實(shí)現(xiàn)自定義累榜;

具體使用可以查看TFTableViewController营勤;總體的邏輯參考RETableViewManager;兩步:

  1. 綁定tableView到MYTableViewManager;
  2. 給tableViewManager手動(dòng)設(shè)置item和itemCell壹罚;
_tableViewManager = [[MYTableViewManager alloc] initWithTableView:self.tableView delegate:nil];
_tableViewManager[@"TFTableviewDefaultItem"] = @"TFTableviewDefaultItemCell";

查看頭文件

@protocol TFTableViewDataSourceDelegate <NSObject>

@required
/**
 *  列表及其控件點(diǎn)擊事件回調(diào)
 *
 *  @param item
 *  @param actionType 事件類型
 */
- (void)actionOnView:(TFTableViewItem *)item actionType:(NSInteger)actionType;
/**
 *  開始加載
 */
- (void)didStartLoad;
/**
 *  加載完成
 *
 *  @param loadPolicy 加載類型
 *  @param object     返回?cái)?shù)據(jù)
 *  @param error      錯(cuò)誤
 */
- (void)didFinishLoad:(TFDataLoadPolicy)loadPolicy object:(id)object error:(NSError *)error;

@optional
- (BOOL)showPullRefresh;

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;

- (void)scrollViewDidScrollUp:(CGFloat)deltaY;

- (void)scrollViewDidScrollDown:(CGFloat)deltaY;

- (void)scrollFullScreenScrollViewDidEndDraggingScrollUp;

- (void)scrollFullScreenScrollViewDidEndDraggingScrollDown;

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;

- (void)tableView:(ASTableView *)tableView willDisplayNodeForRowAtIndexPath:(NSIndexPath *)indexPath;

- (void)tableView:(ASTableView *)tableView didEndDisplayingNode:(ASCellNode *)node forRowAtIndexPath:(NSIndexPath *)indexPath;

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath;

@end

@interface TFTableViewDataSource : NSObject

@property (nonatomic ,weak) id<TFTableViewDataSourceDelegate> delegate;
@property (nonatomic ,strong ,readonly ,getter = manager) MYTableViewManager *manager;
@property (nonatomic ,weak) ASTableView *tableView;
@property (nonatomic ,assign) TFDataSourceState dataSourceState;

/**
 *  總頁(yè)數(shù)
 */
@property (nonatomic ,assign) NSInteger totalPage;

/**
 *  當(dāng)前頁(yè)碼
 */
@property (nonatomic ,assign) NSInteger currentPage;

/**
 *  對(duì)應(yīng)的listType葛作,綁定url
 */
@property (nonatomic ,assign) NSInteger listType;

/**
 *  列表數(shù)據(jù)緩存時(shí)間
 */
@property (nonatomic ,assign) NSInteger cacheTimeInSeconds;

/**
 *  初始化化方法,用于綁定manager和tableview猖凛;item和itemCell赂蠢;
 *
 */
- (instancetype)initWithTableView:(ASTableView *)tableView
                         listType:(NSInteger)listType
                           params:(NSDictionary *)params
                         delegate:(id /*<TFTableViewDataSourceDelegate>*/)delegate;

/**
 *  開始加載,沒有url參數(shù)
 */
- (void)startLoading;

/**
 *  開始加載列表數(shù)據(jù)辨泳,帶url參數(shù)
 *
 *  @param params GET 請(qǐng)求參數(shù)
 */
- (void)startLoadingWithParams:(NSDictionary *)params;

/**
 *  停止加載
 */
- (void)stopLoading;

/**
 *  刷新指定Cell
 *
 *  @param actionType 刷新動(dòng)作
 *  @param identifier Cell唯一標(biāo)示
 */
- (void)refreshCell:(NSInteger)actionType identifier:(NSString *)identifier;


/**
 *  下拉刷新相關(guān)
 */
- (void)initTableViewPullRefresh;
- (void)startTableViewPullRefresh;
- (void)stopTableViewPullRefresh;

@end

查看實(shí)現(xiàn)方法:

一. 初始化init開始虱岂;

- (instancetype)initWithTableView:(ASTableView *)tableView
                         listType:(NSInteger)listType
                           params:(NSDictionary *)params
                         delegate:(id /*<TFTableViewDataSourceDelegate>*/)delegate {
    self = [super init];
    if (!self) {
        return nil;
    }
    _delegate  = delegate;
    _tableView = tableView;
    _listType  = listType;
    _requestArgument = [NSMutableDictionary dictionaryWithDictionary:params];
    _manager = [[MYTableViewManager alloc] initWithTableView:tableView delegate:self];
    [self initTableViewPullRefresh];
    [self setupDataSource];
    return self;
}

初始化請(qǐng)求參數(shù)requestArgument,MYTableViewManager菠红;調(diào)用initTableViewPullRefresh初始化下拉刷新第岖;調(diào)用setupDataSource方法,進(jìn)行一些初始化配置试溯,根據(jù)listType獲取對(duì)應(yīng)的url和dataManager蔑滓;

#pragma mark - 初始化數(shù)據(jù)加載方法
- (void)setupDataSource {
    _downThresholdY = 200.0;
    _upThresholdY = 25.0;
    
    NSString *requestURL = [[TFTableViewDataSourceConfig sharedInstance] requestURLByListType:_listType];
    NSString *className = [[TFTableViewDataSourceConfig sharedInstance] classNameByListType:_listType];
    _dataRequest = [[TFTableViewDataRequest alloc] initWithRequestURL:requestURL params:_requestArgument];
    if (className) {
        Class class = NSClassFromString(className);
        _tableViewDataManager = [[class alloc] initWithDataSource:self listType:_listType];
    }
    //registerClass
    NSArray *itemClassList = [TFTableViewClassList subclassesOfClass:[MYTableViewItem class]];
    for (Class itemClass in itemClassList) {
        NSString *itemName = NSStringFromClass(itemClass);
        self.manager[itemName] = [itemName stringByAppendingString:@"Cell"];
    }
}

在RouteManager中setupMap配置信息如下;

[self mapWithListType:ListTypeManagerCreateList
     dataManagerClass:@"DCManegerDataManeger"
                  url:kDCInterfaceManagerRoot];

看看mapWithListType怎么實(shí)現(xiàn)的遇绞;最后調(diào)用TFTableViewDataSourceConfig方法键袱;

+ (void)mapWithListType:(ListType)listType dataManagerClass:(NSString *)className url:(NSString *)url {
    [[TFTableViewDataSourceConfig sharedInstance]
     mapWithListType:listType
     mappingInfo:@{ kTFTableViewDataManagerClassKey : className,
                    kTFTableViewDataRequestURLKey   : url }];
}

返回查看setupDataSource方法;就獲取到相應(yīng)的requestURL和ViewDataManager類名摹闽;
對(duì)DataManager進(jìn)行實(shí)例化蹄咖;通過(guò)TFTableViewClassList獲取所有MYTableViewItem的子類,這是通過(guò)runtime實(shí)現(xiàn)的付鹿,之后給manger配置item和itemCell澜汤,像下面這樣铝量;

_tableViewManager = [[MYTableViewManager alloc] initWithTableView:self.tableView delegate:nil];
_tableViewManager[@"TFTableviewDefaultItem"] = @"TFTableviewDefaultItemCell";

二. 數(shù)據(jù)加載loading;

// 開始加載银亲,
- (void)startLoading {
    [self startLoadingWithParams:_requestArgument];
}

// 帶參數(shù) 加載慢叨;
- (void)startLoadingWithParams:(NSDictionary *)params {
    if (_requestArgument) {
        [_requestArgument addEntriesFromDictionary:params];
    }
    else {
        _requestArgument = [NSMutableDictionary dictionaryWithDictionary:params];
    }
    [self load:TFDataLoadPolicyNone context:nil];
}

?务蝠?拍谐?疑問(wèn),這樣調(diào)用馏段,參數(shù)會(huì)重復(fù)嗎轩拨;

[self.requestParams setObject:@(model.id) forKey:@"city"];
[self.dataSource startLoadingWithParams:self.requestParams];

數(shù)據(jù)加載核心方法

// 數(shù)據(jù)加載
- (void)load:(TFDataLoadPolicy)loadPolicy context:(ASBatchContext *)context {
    //當(dāng)前正在加載數(shù)據(jù)
    if (_dataSourceState == TFDataSourceStateLoading) {
        return;
    }
    if (loadPolicy == TFDataLoadPolicyMore) {
        //加載下一頁(yè)數(shù)據(jù)
        if (_currentPage == _totalPage) {
            //加載完所有頁(yè)碼
            _dataSourceState = TFDataSourceStateFinished;
            return;
        }
        _currentPage++;
    } else {
        _currentPage = 1;
        _totalPage = 1;
    }
    [_requestArgument setObject:[NSNumber numberWithInteger:[TFTableViewDataSourceConfig pageSize]]
                         forKey:@"pageSize"];
    [_requestArgument setObject:[NSNumber numberWithInteger:_currentPage] forKey:@"currentPage"];
    _dataRequest.requestArgument    = _requestArgument;
    // 設(shè)置緩存時(shí)間
    _dataRequest.cacheTimeInSeconds = _cacheTimeInSeconds;
    // 設(shè)置操作標(biāo)示
    _dataSourceState = TFDataSourceStateLoading;
    // 加載第一頁(yè)時(shí)候使用緩存數(shù)據(jù)
    if ([_dataRequest cacheResponseObject] && !_firstLoadOver) {
        // 使用緩存數(shù)據(jù)繪制UI
        TFTableViewLogDebug(@"use cache data for %@",_dataRequest.requestURL);
        [self handleResultData:[_dataRequest cacheResponseObject]
                dataLoadPolicy:TFDataLoadPolicyCache
                       context:context
                         error:nil];
    }
    else {
        // 請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)
        [_dataRequest startWithCompletionBlockWithSuccess:^(__kindof TFBaseRequest *request) {
            TFTableViewLogDebug(@"get data from server %@ page:%@",request.requestUrl,@(_currentPage));
            [self handleResultData:request.responseObject dataLoadPolicy:loadPolicy context:context error:nil];
        } failure:^(__kindof TFBaseRequest *request) {
            TFTableViewLogDebug(@"get data from %@ error :%@ userinfo:%@",request.requestUrl,request.error,request.userInfo);
            // 網(wǎng)絡(luò)請(qǐng)求出錯(cuò),存在緩存院喜,先獲取緩存
            if ([request cacheResponseObject]) {
                [self handleResultData:[request cacheResponseObject]
                        dataLoadPolicy:loadPolicy
                               context:context
                                 error:nil];
            }
            else {
                [self handleResultData:nil
                        dataLoadPolicy:loadPolicy
                               context:context
                                 error:request.error];
            }
        }];
    }
}

設(shè)置請(qǐng)求參數(shù)亡蓉、請(qǐng)求緩存時(shí)間;有緩存先用緩存繪制UI喷舀,不然網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)砍濒;網(wǎng)絡(luò)請(qǐng)求出現(xiàn)錯(cuò)誤的時(shí)候,也會(huì)先使用緩存硫麻;

// 處理返回?cái)?shù)據(jù)并繪制UI
- (void)handleResultData:(NSDictionary *)result
          dataLoadPolicy:(TFDataLoadPolicy)dataLoadPolicy
                 context:(ASBatchContext *)context
                   error:(NSError *)error {
    TFTableViewLogDebug(@"%s",__func__);
    NSError *hanldeError = nil;
    NSInteger lastSectionIndex = [[self.manager sections] count] - 1;
    if (!result || [[result objectForKey:@"dataList"] count] <= 0) {
        //數(shù)據(jù)為空
        hanldeError = [NSError errorWithDomain:@"" code:1 userInfo:@{}];
    }
    if (dataLoadPolicy == TFDataLoadPolicyMore) {
        //加載下一頁(yè)爸邢,移除loading item
        [self.manager removeLastSection];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:lastSectionIndex]
                          withRowAnimation:UITableViewRowAnimationFade];
        });
    }
    [self setTotalPage:[[result objectForKey:@"totalPage"] integerValue]];
    if (_totalPage == 0) {
        //數(shù)據(jù)邊界檢查
        _totalPage = 1;
        _currentPage = 1;
    }
    
    // 調(diào)用tableViewManager 的 reloadView:block方法 顯示列表數(shù)據(jù);
    // 在這里將數(shù)據(jù)傳給DataManager的子類拿愧;調(diào)用block
    __weak __typeof(self)weakSelf = self;
    [self.tableViewDataManager reloadView:result
                                    block:^(BOOL finished, id object, NSError *error, NSArray <MYTableViewSection *> *sections)
     {
         typeof(self) strongSelf = weakSelf;
         if (finished) {
             if (dataLoadPolicy == TFDataLoadPolicyReload || dataLoadPolicy == TFDataLoadPolicyNone) {
                 // 重新加載列表數(shù)據(jù)
                 [strongSelf.manager removeAllSections];
             }
             NSInteger rangelocation = [strongSelf.manager.sections count];
             [strongSelf.manager addSectionsFromArray:sections];
             NSInteger rangelength = 1;
             // 需要在主線程執(zhí)行
             if (_currentPage < _totalPage) {
                 // 存在下一頁(yè)數(shù)據(jù)杠河,在列表尾部追加loading item
                 MYTableViewSection *section = [MYTableViewSection section];
                 // loading item
                 [section addItem:[MYTableViewLoadingItem itemWithTitle:NSLocalizedString(@"正在加載...", nil)]];
                 [strongSelf.manager addSection:section];
                 rangelength += sections.count;
             }
             dispatch_async(dispatch_get_main_queue(), ^{
                 if (dataLoadPolicy == TFDataLoadPolicyMore) {
                     [strongSelf.tableView insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(rangelocation, rangelength)]
                                         withRowAnimation:UITableViewRowAnimationFade];
                     if (context) {
                         [context completeBatchFetching:YES];
                     }
                 }
                 else {
                     [strongSelf reloadTableView];
                     strongSelf.firstLoadOver = YES;
                     if (dataLoadPolicy == TFDataLoadPolicyReload) {
                         [strongSelf stopTableViewPullRefresh];
                     }
                     if (dataLoadPolicy == TFDataLoadPolicyCache) {
                         //第一次從緩存加載數(shù)據(jù)后延遲觸發(fā)下拉刷新重新加載
                         [strongSelf performSelector:@selector(startTableViewPullRefresh)
                                          withObject:nil
                                          afterDelay:0.75];
                     }
                 }
                 // 數(shù)據(jù)加載完成
                 if (strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(didFinishLoad:object:error:)]) {
                     [strongSelf.delegate didFinishLoad:dataLoadPolicy object:object error:error?error:hanldeError];
                 }
             });
             strongSelf.dataSourceState = TFDataSourceStateFinished;
         }
     }];
}


調(diào)用tableViewManager 的 reloadView:block方法 顯示列表數(shù)據(jù);在這里將數(shù)據(jù)傳給DataManager的子類浇辜;調(diào)用block券敌;

// 重新加載列表數(shù)據(jù);remove所有section了柳洋;
[strongSelf.manager removeAllSections];

最后數(shù)據(jù)加載完成待诅,回調(diào)dataSource的代理(通常為TFTableView的子類);
didFinishLoad:object:error:

通過(guò)源碼看到膳灶,reloadView中將數(shù)據(jù)通過(guò)block傳過(guò)去咱士,在VC中didFinishLoad才能進(jìn)行判斷;
DataManager 給 ViewController 傳數(shù)據(jù)轧钓;
??? 那反過(guò)來(lái)呢;

typedef void (^TableViewReloadCompletionBlock)(BOOL finished,id object,NSError *error, NSArray <MYTableViewSection *> *sections);

- (void)reloadView:(NSDictionary *)result block:(TableViewReloadCompletionBlock)completionBlock

completionBlock(YES, list, nil, @[section]);

- (void)didFinishLoad:(TFDataLoadPolicy)loadPolicy object:(id)object error:(NSError *)error
{
    [super didFinishLoad:loadPolicy object:object error:error];
    
    if (!object)
    {
        [self showStateView:kTFViewStateNoData];
    }
}

MYTableViewManager

最終tableView的cell繪制都在這個(gè)MYTableViewManager中锐膜;
MYTableViewManager的整體邏輯可以參考RETableViewManager;只是將RE里的UITableView
換成ASTableView毕箍;

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

// 返回對(duì)應(yīng)的cell;ASTableView中稱為node道盏;
- (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath

// tableView的側(cè)邊IndexTitles
- (NSArray *)sectionIndexTitlesForTableView:(ASTableView *)tableView

// tableView尾視圖Header 的 title
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

// tableView尾視圖Footer 的 title
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section

// tableView移動(dòng)move
// 可以看到moveHandler而柑、moveCompletionHandler功能文捶;怎么用的
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath

// 看到給item添加editingStyle,就能實(shí)現(xiàn)左劃刪除等媒咳;
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath


- (void)tableView:(ASTableView *)tableView willDisplayNodeForRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(ASTableView *)tableView didEndDisplayingNode:(ASCellNode *)node forRowAtIndexPath:(NSIndexPath *)indexPath


tableView如何實(shí)現(xiàn)刪除粹排,

// tableView如何實(shí)現(xiàn)刪除; section刪掉,tableView刪掉涩澡,還要修改后面
[section removeItemAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

for (NSInteger i = indexPath.row; i < section.items.count; i++) {
    MYTableViewItem *afterItem = [[section items] objectAtIndex:i];
    MYTableViewCell *cell = (MYTableViewCell *)[(ASTableView *)tableView nodeForRowAtIndexPath:afterItem.indexPath];
    cell.rowIndex--;
}

Tableview delegate

// Header顽耳、Footer
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section

- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section

- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section

- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section

// header、Footer的高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionIndex

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)sectionIndex

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)sectionIndex

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)sectionIndex

// Accessories (disclosures).
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath

// Selection
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath

tableView 事件處理

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath

- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath

// Editing
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath

// 左滑刪除妙同、標(biāo)題射富;
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath

- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath

// Moving/reordering

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath

// Indentation

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath

// Copy/Paste.  All three methods must be implemented by the delegate.
// 復(fù)制/粘貼;
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath

- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender

其他的代理不看了粥帚;分析下tableView的事件處理胰耗;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [_tableView deselectRowAtIndexPath:indexPath animated:YES];
    [_tableView beginUpdates];
    MYTableViewSection *section = [self.mutableSections objectAtIndex:indexPath.section];
    id item = [section.items objectAtIndex:indexPath.row];
    if ([item respondsToSelector:@selector(setSelectionHandler:)]) {
        MYTableViewItem *actionItem = (MYTableViewItem *)item;
        if (actionItem.selectionHandler)
            actionItem.selectionHandler(item);
    }
    
    // Forward to UITableView delegate
    //
    if ([self.delegate conformsToProtocol:@protocol(UITableViewDelegate)] && [self.delegate respondsToSelector:@selector(tableView:didSelectRowAtIndexPath:)])
        [self.delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
    
    [_tableView endUpdates];
}

獲取相應(yīng)的section,獲取item芒涡;調(diào)用item的selectionHandler柴灯,并將item作為block參數(shù)回傳過(guò)去;

TFTableViewItem 在初始化會(huì)設(shè)置selectionHandler

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }
    __weak typeof(self) weakself = self;
    self.selectionHandler = ^(id item){
        if (weakself.onViewClickHandler) {
            weakself.onViewClickHandler(item, -1);
        }
    };
    return self;
}

+ (instancetype)itemWithModel:(NSObject *)model
                     clickHandler:(void(^)(TFTableViewItem *item,NSInteger actionType))clickHandler {
    
    TFTableViewItem *item = [[[self class] alloc] init];
    item.model = model;
    item.onViewClickHandler = clickHandler;
    return item;
}

在init中將actionType設(shè)為-1费尽;作為整個(gè)cell的點(diǎn)擊弛槐;其他非零值可以為cell上的按鈕;并且將item值回傳給onViewClickHandler依啰;

TFTableViewDataManager中會(huì)初始化cellViewClickHandler乎串;其中的item是TFTableViewItem傳過(guò)來(lái)的;

- (instancetype)initWithDataSource:(TFTableViewDataSource *)tableViewDataSource
                          listType:(NSInteger)listType {
    self = [super init];
    if (!self) {
        return nil;
    }
    _tableViewDataSource = tableViewDataSource;
    _listType = listType;
    __weak __typeof(self)weakSelf = self;
    _cellViewClickHandler = ^ (TFTableViewItem *item ,NSInteger actionType) {
        __typeof(&*weakSelf) strongSelf = weakSelf;
        strongSelf.currentIndexPath = item.indexPath;
        [item deselectRowAnimated:YES];
        if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) {
            [strongSelf.tableViewDataSource.delegate actionOnView:item actionType:actionType];
        }
        [strongSelf cellViewClickHandler:item actionType:actionType];
    };
    
    _deleteHanlder = ^(TFTableViewItem *item ,Completion completion) {
        __typeof(&*weakSelf) strongSelf = weakSelf;
        [strongSelf deleteHanlder:item completion:completion];
    };
    return self;
}

cellViewClickHandler中速警,
首先會(huì)調(diào)用tableViewDataSource.delegate的方法actionOnView:actionType:叹誉; 一般為TFTableViewController的子類;
然后再調(diào)用對(duì)應(yīng)TFTableViewDataManager子類的cellViewClickHandler:actionType:

Objective-C如何自己實(shí)現(xiàn)一個(gè)基于數(shù)組下標(biāo)的屬性訪問(wèn)模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闷旧,一起剝皮案震驚了整個(gè)濱河市长豁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忙灼,老刑警劉巖匠襟,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異该园,居然都是意外死亡酸舍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門里初,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)啃勉,“玉大人,你說(shuō)我怎么就攤上這事双妨』床” “怎么了叮阅?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)泣特。 經(jīng)常有香客問(wèn)我浩姥,道長(zhǎng),這世上最難降的妖魔是什么状您? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任勒叠,我火速辦了婚禮,結(jié)果婚禮上竞阐,老公的妹妹穿的比我還像新娘缴饭。我一直安慰自己,他們只是感情好骆莹,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布颗搂。 她就那樣靜靜地躺著,像睡著了一般幕垦。 火紅的嫁衣襯著肌膚如雪丢氢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天先改,我揣著相機(jī)與錄音疚察,去河邊找鬼。 笑死仇奶,一個(gè)胖子當(dāng)著我的面吹牛貌嫡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播该溯,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼岛抄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了狈茉?” 一聲冷哼從身側(cè)響起夫椭,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氯庆,沒想到半個(gè)月后蹭秋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡堤撵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年仁讨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粒督。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陪竿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屠橄,到底是詐尸還是另有隱情族跛,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布锐墙,位于F島的核電站礁哄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏溪北。R本人自食惡果不足惜桐绒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望之拨。 院中可真熱鬧茉继,春花似錦、人聲如沸蚀乔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吉挣。三九已至派撕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間睬魂,已是汗流浹背终吼。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氯哮,地道東北人际跪。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喉钢,于是被迫代替她去往敵國(guó)和親姆打。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 許多 iOS 應(yīng)用程序向用戶顯示列表項(xiàng)出牧,并允許用戶選擇穴肘,刪除或重新排列列表項(xiàng)。 不管是顯示用戶地址簿中的人員列表的...
    titvax閱讀 1,515評(píng)論 2 1
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中舔痕。评抚。。 其實(shí)如果沒有APIManager這一層是沒法使用delegate的伯复,畢竟多個(gè)單...
    yhtang閱讀 5,207評(píng)論 1 23
  • 2017.02.22 可以練習(xí)慨代,每當(dāng)這個(gè)時(shí)候,腦袋就犯困啸如,我這腦袋真是神奇呀侍匙,一說(shuō)讓你做事情,你就犯困叮雳,你可不要太...
    Carden閱讀 1,349評(píng)論 0 1
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)想暗、插件妇汗、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,124評(píng)論 4 61
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,325評(píng)論 25 707