99#import " TJPNetworkDefine.h"
1010#import " TJPViperDefaultErrorHandler.h"
1111#import " TJPMemoryCache.h"
12+ #import " TJPPaginationInfo.h"
1213
1314@interface TJPViperBaseInteractorImpl ()
1415
@@ -19,6 +20,11 @@ @interface TJPViperBaseInteractorImpl ()
1920@property (nonatomic , strong ) NSMutableSet <NSString *> *subscribedTopics;
2021
2122
23+ // 分页相关属性
24+ @property (nonatomic , strong ) TJPPaginationInfo *currentPagination;
25+ @property (nonatomic , assign ) NSInteger currentPage;
26+ @property (nonatomic , assign ) BOOL hasMoreData;
27+ 2228@end
2329
2430
@@ -42,6 +48,12 @@ - (instancetype)init {
4248 _uploadProgressMap = [NSMutableDictionary dictionary ];
4349 _subscribedTopics = [NSMutableSet set ];
4450
51+ // 分页相关初始化
52+ _defaultPageSize = 10 ;
53+ _currentPage = 0 ;
54+ _hasMoreData = YES ;
55+ _currentPagination = nil ;
56+ 4557 [self setupInteractor ];
4658 _isInitialized = YES ;
4759
@@ -74,8 +86,20 @@ - (RACSubject *)navigateToPageSubject {
7486
7587#pragma mark - Load Data
7688- (void )fetchDataForPageWithCompletion : (NSInteger )page success : (void (^)(NSArray * _Nullable, NSInteger ))success failure : (void (^)(NSError * _Nullable))failure {
77- // 提供标准接口 子类需要重写此方法并实现具体的业务逻辑
78- TJPLOG_INFO (@" [%@ ] BaseInteractor 提供了一个标准接口 - fetchDataForPageWithCompletion" , NSStringFromClass ([self class ]));
89+ // 调用新方法并适配旧接口
90+ [self fetchDataForPageWithPagination: page success: ^(NSArray * _Nullable data, TJPPaginationInfo * _Nullable pagination) {
91+ if (success) {
92+ NSInteger totalPage = pagination.paginationType == TJPPaginationTypePageBased ? pagination.totalPages : 0 ;
93+ success (data, totalPage);
94+ }
95+ } failure: failure];
96+ }
97+ 98+ - (void )fetchDataForPageWithPagination : (NSInteger )page
99+ success : (void (^)(NSArray * _Nullable, TJPPaginationInfo * _Nullable))success
100+ failure : (void (^)(NSError * _Nullable))failure {
101+ 102+ TJPLOG_INFO (@" [%@ ] 开始请求第 %ld 页数据(带分页信息)" , NSStringFromClass ([self class ]), (long )page);
79103
80104 // 参数验证
81105 if (page <= 0 ) {
@@ -86,34 +110,60 @@ - (void)fetchDataForPageWithCompletion:(NSInteger)page success:(void (^)(NSArray
86110 return ;
87111 }
88112
113+ // 检查是否可以加载下一页
114+ if (page > 1 && _currentPagination && !_currentPagination.canLoadNextPage ) {
115+ NSError *error = [NSError errorWithDomain: TJPViperErrorDomain
116+ code: TJPViperErrorBusinessLogicFailed
117+ userInfo: @{NSLocalizedDescriptionKey : @" 没有更多数据" }];
118+ if (failure) failure (error);
119+ return ;
120+ }
121+ 122+ // 检查缓存
123+ NSString *cacheKey = [self cacheKeyForPage: page];
124+ NSString *paginationCacheKey = [self paginationCacheKeyForPage: page];
89125
126+ NSArray *cachedData = [self .cacheManager loadCacheForKey: cacheKey];
127+ TJPPaginationInfo *cachedPagination = [self loadCachedPaginationForPage: page];
90128
91- // 如果是基类被直接调用,抛出标准的TJPNetworkError
129+ if (cachedData && cachedPagination) {
130+ TJPLOG_INFO (@" [%@ ] 返回第 %ld 页缓存数据" , NSStringFromClass ([self class ]), (long )page);
131+ [self updatePaginationInfo: cachedPagination];
132+ if (success) success (cachedData, cachedPagination);
133+ return ;
134+ }
135+ 136+ // 如果是基类被直接调用,抛出错误
92137 if ([self isMemberOfClass: [TJPViperBaseInteractorImpl class ]]) {
93138 NSError *error = [NSError errorWithDomain: TJPViperErrorDomain
94139 code: TJPViperErrorBusinessLogicFailed
95140 userInfo: @{NSLocalizedDescriptionKey : @" 子类必须重写此方法" }];
96141 if (failure) failure (error);
97142 return ;
98143 }
99- 100- TJPLOG_INFO (@" [%@ ] 正在请求第 %ld 页的数据" , NSStringFromClass ([self class ]), (long )page);
101144
102145 // 执行具体的数据请求(由子类实现)
103- [self performDataRequestForPage: page completion : ^(NSArray *data, NSInteger totalPage , NSError *error) {
146+ [self performDataRequestForPage: page withPagination : ^(NSArray *data, TJPPaginationInfo *pagination , NSError *error) {
104147 if (error) {
105148 TJPLOG_ERROR (@" 数据请求失败: %@ " , error.localizedDescription );
106149 if (failure) failure (error);
107150 } else {
108151 TJPLOG_INFO (@" 数据请求成功: %lu 条数据" , (unsigned long )data.count );
109152
110- // 缓存数据
153+ // 更新分页信息
154+ if (pagination) {
155+ [self updatePaginationInfo: pagination];
156+ }
157+ 158+ // 缓存数据和分页信息
111159 if ([self shouldCacheDataForPage: page] && data.count > 0 ) {
112- NSString *cacheKey = [self cacheKeyForPage: page];
113160 [self .cacheManager saveCacheWithData: data forKey: cacheKey expireTime: TJPCacheExpireTimeMedium];
161+ if (pagination) {
162+ [self cachePaginationInfo: pagination forPage: page];
163+ }
114164 }
115165
116- if (success) success (data, totalPage );
166+ if (success) success (data, pagination );
117167 }
118168 }];
119169}
@@ -211,16 +261,59 @@ - (void)searchDataWithKeyword:(NSString *)keyword filters:(NSDictionary *)filter
211261 });
212262}
213263
264+ - (TJPPaginationInfo * _Nullable)extractPaginationFromResponse : (id )rawData {
265+ // 基类提供默认实现,子类可重写
266+ if ([rawData isKindOfClass: [NSDictionary class ]]) {
267+ NSDictionary *dict = (NSDictionary *)rawData;
268+ NSDictionary *paginationDict = dict[@" pagination" ] ?: dict[@" page_info" ] ?: dict[@" paging" ];
269+ 270+ if (paginationDict) {
271+ return [TJPPaginationInfo paginationWithDict: paginationDict];
272+ }
273+ }
274+ return nil ;
275+ }
276+ 214277#pragma mark - Manage Cache
278+ - (NSString *)paginationCacheKeyForPage : (NSInteger )page {
279+ return [NSString stringWithFormat: @" %@ _pagination_page_%ld " , NSStringFromClass ([self class ]), (long )page];
280+ }
281+ 282+ - (void )cachePaginationInfo : (TJPPaginationInfo *)pagination forPage : (NSInteger )page {
283+ NSString *cacheKey = [self paginationCacheKeyForPage: page];
284+ NSDictionary *paginationDict = [pagination toDictionary ];
285+ [self .cacheManager saveCacheWithData: paginationDict forKey: cacheKey expireTime: TJPCacheExpireTimeMedium];
286+ 287+ TJPLOG_INFO (@" [%@ ] 缓存第 %ld 页分页信息" , NSStringFromClass ([self class ]), (long )page);
288+ }
289+ 290+ - (TJPPaginationInfo * _Nullable)loadCachedPaginationForPage : (NSInteger )page {
291+ NSString *cacheKey = [self paginationCacheKeyForPage: page];
292+ NSDictionary *cachedDict = [self .cacheManager loadCacheForKey: cacheKey];
293+ 294+ if (cachedDict && [cachedDict isKindOfClass: [NSDictionary class ]]) {
295+ TJPLOG_INFO (@" [%@ ] 加载第 %ld 页缓存分页信息" , NSStringFromClass ([self class ]), (long )page);
296+ return [TJPPaginationInfo paginationWithDict: cachedDict];
297+ }
298+ 299+ return nil ;
300+ }
215301
216302- (void )clearCache : (NSString *)cacheKey {
217303 TJPLOG_INFO (@" [%@ ] 清理缓存,缓存键: %@ " , NSStringFromClass ([self class ]), cacheKey);
218304 [self .cacheManager removeCacheForKey: cacheKey];
305+ 306+ // 同时清理对应的分页缓存
307+ if ([cacheKey containsString: @" _page_" ]) {
308+ NSString *paginationCacheKey = [cacheKey stringByReplacingOccurrencesOfString: @" _page_" withString: @" _pagination_page_" ];
309+ [self .cacheManager removeCacheForKey: paginationCacheKey];
310+ }
219311}
220312
221313- (void )clearAllCache {
222314 TJPLOG_INFO (@" [%@ ] 清理所有缓存" , NSStringFromClass ([self class ]));
223315 [self .cacheManager clearAllCache ];
316+ [self resetPagination ]; // 同时重置分页信息
224317}
225318
226319- (NSUInteger )getCacheSize {
@@ -354,11 +447,22 @@ - (NSError * _Nullable)validateBusinessRules:(NSDictionary *)data {
354447#pragma mark - Abstract Methods
355448- (void )performDataRequestForPage : (NSInteger )page
356449 completion : (void (^)(NSArray * _Nullable, NSInteger , NSError * _Nullable))completion {
357- // 这是抽象方法,子类必须实现
450+ // 调用新的带分页信息的方法
451+ [self performDataRequestForPage: page withPagination: ^(NSArray * _Nullable data, TJPPaginationInfo * _Nullable pagination, NSError * _Nullable error) {
452+ if (completion) {
453+ NSInteger totalPage = pagination && pagination.paginationType == TJPPaginationTypePageBased ? pagination.totalPages : 0 ;
454+ completion (data, totalPage, error);
455+ }
456+ }];
457+ }
458+ 459+ - (void )performDataRequestForPage : (NSInteger )page
460+ withPagination : (void (^)(NSArray * _Nullable, TJPPaginationInfo * _Nullable, NSError * _Nullable))completion {
461+ // 这是新的抽象方法,子类必须实现
358462 NSError *error = [NSError errorWithDomain: TJPViperErrorDomain
359463 code: TJPViperErrorBusinessLogicFailed
360- userInfo: @{NSLocalizedDescriptionKey : @" 子类必须实现performDataRequestForPage:completion :方法" }];
361- if (completion) completion (nil , 0 , error);
464+ userInfo: @{NSLocalizedDescriptionKey : @" 子类必须实现performDataRequestForPage:withPagination :方法" }];
465+ if (completion) completion (nil , nil , error);
362466}
363467
364468#pragma mark - Methods for Subclass Override
@@ -421,9 +525,65 @@ - (void)teardownInteractor {
421525 // 清理上传进度
422526 [self .uploadProgressMap removeAllObjects ];
423527
528+ // 清理分页信息
529+ [self resetPagination ];
530+ 531+ 424532 // 子类可重写此方法进行清理工作
425533}
426534
535+ #pragma mark - Pagination Management
536+ - (void )resetPagination {
537+ _currentPage = 0 ;
538+ _hasMoreData = YES ;
539+ _currentPagination = nil ;
540+ 541+ TJPLOG_INFO (@" [%@ ] 分页信息已重置" , NSStringFromClass ([self class ]));
542+ }
543+ 544+ - (void )updatePaginationInfo : (TJPPaginationInfo *)paginationInfo {
545+ NSLog (@" [DEBUG] updatePaginationInfo 接收到的分页信息:" );
546+ NSLog (@" - currentPage: %ld " , (long )paginationInfo.currentPage );
547+ NSLog (@" - hasMore: %@ " , paginationInfo.hasMore ? @" YES" : @" NO" );
548+ NSLog (@" - getNextPageNumber: %ld " , (long )paginationInfo.getNextPageNumber );
549+ NSLog (@" - paginationType: %ld " , (long )paginationInfo.paginationType );
550+ 551+ _currentPagination = [paginationInfo copy ];
552+ 553+ if (paginationInfo.paginationType == TJPPaginationTypePageBased) {
554+ _currentPage = paginationInfo.currentPage ;
555+ _hasMoreData = paginationInfo.hasMore ;
556+ } else {
557+ // 游标分页时,currentPage 用于记录已加载的页面数
558+ _currentPage = _currentPage > 0 ? _currentPage : 1 ;
559+ _hasMoreData = paginationInfo.hasMore ;
560+ }
561+ 562+ TJPLOG_INFO (@" [%@ ] 分页信息已更新: %@ " , NSStringFromClass ([self class ]), paginationInfo.debugDescription );
563+ }
564+ 565+ - (BOOL )canLoadNextPage {
566+ NSLog (@" [DEBUG] canLoadNextPage: hasMoreData=%@ , currentPage=%ld " , _hasMoreData ? @" YES" : @" NO" , (long )self.currentPage );
567+ return _hasMoreData && _currentPagination.canLoadNextPage ;
568+ }
569+ 570+ - (NSInteger )getNextPageNumber {
571+ NSInteger nextPage;
572+ if (!_currentPagination) {
573+ nextPage = 1 ;
574+ } else if (_currentPagination.paginationType == TJPPaginationTypePageBased) {
575+ nextPage = _currentPagination.getNextPageNumber ;
576+ } else {
577+ nextPage = _currentPage + 1 ;
578+ }
579+ 580+ NSLog (@" [DEBUG] getNextPageNumber: currentPage=%ld , nextPage=%ld " , (long )_currentPage, (long )nextPage);
581+ NSLog (@" [DEBUG] 调用栈: %@ " , [NSThread callStackSymbols ]);
582+ 583+ return nextPage;
584+ }
585+ 586+ 427587#pragma mark - Private Methods
428588
429589- (void )simulateRealTimeDataForTopic : (NSString *)topic {
0 commit comments