A包含B,如何实现A和B互相调用更新数据。
添加通知了不是立即生效的,需要系统调度。而block是立即生效的。
不要用通知来回发送通知,通知有很多弊端,特别是多线程环境下,当一个控件刚添加了通知还没有正式生效,另一个线程发送了对应通知,就有概率闪退 。
所以尽量少用或不用通知,尽量用block来代替。
理论上因为A包含B,A可以知道B的数据,但是无法知道B的私有数据,当然若A只是创建B,但是没有持有B的指针也无法知道B的数据。通过两者来回发送通知当然能实现,只是通知是一对多,有概率闪退的问题,尽量别用。那么可以在创建B时给它传递一个bock,对A特别关注的数据B更新该数据时同步给A。
现在是一个A页面通过蘑菇街架构创建了一个B页面并把一个block给B页面,A页面没有持有B页面的指针,当B页面更新了数据后,通过block的回掉更新了A页面的数据和刷新了列表。
A页面创建B页面:
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; void(^selectEntityBlock)(FHFollowListUnitEntity *followListUnitEntity, BOOL isFollow) = ^(FHFollowListUnitEntity *followListUnitEntity, BOOL isFollow) { @strongify(self); [self freshTabWithFollowListUnitEntity:followListUnitEntity isFollow:isFollow]; }; [userInfo setSafeObject:entity forKey:@"followListUnitEntity"]; [userInfo setSafeObject:selectEntityBlock forKey:@"block"]; [userInfo setSafeObject:@(entity.dynamic_id) forKey:@"dynamic_id"]; [BITRouter openURL:@"gb://FHImageTextDetailViewController" withUserInfo:userInfo completion:nil];
A页面通过B页面的回调数据更新数据并刷新表格处理:
-(void)freshTabWithFollowListUnitEntity:(FHFollowListUnitEntity *)followListUnitEntity isFollow:(BOOL)isFollow { if(!followListUnitEntity || ![followListUnitEntity isKindOfClass:[FHFollowListUnitEntity class]] || isCommonUnitEmptyArray(self.models)) { return; } if(!isFollow) { for(NSInteger i = 0; i < self.models.count; i++) { FHFollowListUnitEntity *entity = self.models[i]; if(entity && [entity isKindOfClass:[FHFollowListUnitEntity class]] && followListUnitEntity.dynamic_id > 0 && (entity.dynamic_id == followListUnitEntity.dynamic_id)) { entity.is_collect = followListUnitEntity.is_collect; entity.collect = followListUnitEntity.collect; entity.is_praise = followListUnitEntity.is_praise; entity.praise = followListUnitEntity.praise; entity.is_evaluate = followListUnitEntity.is_evaluate; entity.evaluate = followListUnitEntity.evaluate; // [self.collectionView reloadData]; if(self.selectEntityBlock) { self.selectEntityBlock(followListUnitEntity, NO); } BOOL animationsEnabled = [UIView areAnimationsEnabled]; [UIView setAnimationsEnabled:NO]; NSIndexPath *indexPath=[NSIndexPath indexPathForRow:i inSection:0]; [self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObjects:indexPath,nil]]; [UIView setAnimationsEnabled:animationsEnabled]; return; } } } else { if(isCommonUnitEmptyString(followListUnitEntity.user_id)) { return; } BOOL flag = NO; NSMutableArray *indexPaths = [NSMutableArray array]; for(NSInteger i = 0; i < self.models.count; i++) { FHFollowListUnitEntity *entity = self.models[i]; if(entity && [entity isKindOfClass:[FHFollowListUnitEntity class]] && followListUnitEntity.dynamic_id > 0 && ([entity.user_id isEqualToString:followListUnitEntity.user_id])) { flag = YES; entity.is_follow = followListUnitEntity.is_follow; entity.follow_sum = followListUnitEntity.follow_sum; [indexPaths addSafeObject:[NSIndexPath indexPathForRow:i inSection:0]]; // NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:i]; // //为了避免重新加载时出现不需要的动画(又名“闪烁”) // BOOL animationsEnabled = [UIView areAnimationsEnabled]; // [UIView setAnimationsEnabled:NO]; // [self.collectionView reloadSections:indexSet]; // [UIView setAnimationsEnabled:animationsEnabled]; // return; } } if(flag) { BOOL animationsEnabled = [UIView areAnimationsEnabled]; [UIView setAnimationsEnabled:NO]; [self.collectionView reloadItemsAtIndexPaths:indexPaths]; [UIView setAnimationsEnabled:animationsEnabled]; // [self.collectionView reloadData]; if(self.selectEntityBlock) { self.selectEntityBlock(followListUnitEntity, YES); } } } }
B页面通过block回调A页面注册的block传递数据:
B页的子控件更新了数据,回调给B页面,然后回调A页面的block:
self.writeEvaluateMessageCollectPraiseView.selectBlock = ^{ @strongify(self); CHECK_JUMP_LOGIN; NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; void(^freshBlock)(NSInteger dynamic_id, BOOL is_evaluate, NSInteger evaluate) = ^(NSInteger dynamic_id, BOOL is_evaluate, NSInteger evaluate){ @strongify(self); if(dynamic_id > 0 && self.followListUnitEntity && (self.followListUnitEntity.dynamic_id == dynamic_id)) { self.model.detailEntity.is_evaluate = is_evaluate; self.model.detailEntity.evaluate = evaluate; self.writeEvaluateMessageCollectPraiseView.model = self.model; self.followListUnitEntity.is_evaluate = self.model.detailEntity.is_evaluate; self.followListUnitEntity.evaluate = self.model.detailEntity.evaluate; self.selectEntityBlock(self.followListUnitEntity, NO); } // [self loadListDataWithIsFresh:YES]; }; [userInfo setSafeObject:freshBlock forKey:@"block"]; [userInfo setSafeObject:@(self.model.dynamic_id) forKey:@"dynamic_id"]; [BITRouter openURL:@"gb://FHEvaluateListViewController" withUserInfo:userInfo completion:nil]; };
B页通过请求数据更新了数据,回调A页面的block:
-(void)loadListDataWithIsFresh:(BOOL)isFresh { @weakify(self); self.isFresh = isFresh; [NetWorkManager postWithPath:@"Dynamic/getDynamic" param:@{@"typeid":@(1),@"dynamic_id":@(self.model.dynamic_id)} dataClass:[FHDetailEntity class] isArray:NO].complete = ^(DYNetModel * _Nullable net, FHDetailEntity *data) { @strongify(self); if (net.errcode == DYNetModelStateSuccess) { self.isFresh = NO; if(data && [data isKindOfClass:[FHDetailEntity class]]) { if(isFresh) { if(self.selectEntityBlock && self.selectEntityBlock && [self.followListUnitEntity isKindOfClass:[FHFollowListUnitEntity class]]) { self.model.detailEntity.is_follow = data.is_follow; self.model.detailEntity.is_collect = data.is_collect; self.model.detailEntity.collect = data.collect; self.model.detailEntity.is_praise = data.is_praise; self.model.detailEntity.praise = data.praise; self.model.detailEntity.is_evaluate = data.is_evaluate; self.model.detailEntity.evaluate = data.evaluate; [self freshBlock]; self.writeEvaluateMessageCollectPraiseView.model = self.model; } return; } self.model.detailEntity = data; [self.collectionView reloadData]; self.selectBtn.isSelectContent = self.model.detailEntity.is_collect; self.writeEvaluateMessageCollectPraiseView.model = self.model; } else { [self displayNoData]; } } else { [self loadFail]; } }; }
理论上因为是B是被包含的关系,无法直接访问A的数据,而A的数据可能被C直接更新的,也可能是A自己更新的数据,情况比较复杂,若A的数据变更时,忘记传递给B,就会造成B拿到的不是A的最新数据。若B只在部分处理时需要使用A的数据。正确的做法是A创建B注册一个B的block,B需要时,调用block通知A更新最新的B关注数据给B或单例。然后再使用数据。block是实时传递,不像通知在发出通知到收到通知需要时间差。
A页面创建B页面注册一个B页面的block:
- (UIViewController<ZJScrollPageViewChildVcDelegate> *)childViewController:(UIViewController<ZJScrollPageViewChildVcDelegate> *)reuseViewController forIndex:(NSInteger)index { @weakify(self); if(self.currentCell && self.player){ self.currentCell.isPause = YES; [self.player clearPlayer]; //返回关注的列表,暂停之前的播放 [self.player stopPlay]; } self.currentIndex = index; UIViewController<ZJScrollPageViewChildVcDelegate> *childVc = reuseViewController; if (!childVc) { if (index == 0) { self.attentionBtn.isSelected = YES; self.recommentBtn.isSelected = NO; QRHomeController *vc = [[QRHomeController alloc] init]; self.attentionPage = vc; vc.type = @"2"; // vc.isFirstLoad = YES; vc.isFreshTable = YES; // self.isLoadCurrencyStartup = NO; [self synchroData]; self.attentionPage.synchroDataBlock = ^{ @strongify(self); [self synchroData]; }; self.attentionPage.switchSelectPageBlock = ^(NSInteger selectPageIndex) { @strongify(self); [self synchroData]; [self.scrollPageView setSelectedIndex:1 animated:YES]; }; self.attentionPage.storeDataBlock = ^{ @strongify(self); [self storeWithPage:self.attentionPage sno:0]; }; self.attentionPage.freshPageBlock = ^(NSInteger freshPageIndex) { @strongify(self); if(0 == freshPageIndex) { [self.attentionPage headerRefresh]; } else { [self.recommentPage headerRefresh]; } }; [self.attentionPage headerRefresh]; childVc = vc; } else { self.attentionBtn.isSelected = NO; self.recommentBtn.isSelected = YES; QRHomeController *vc = [[QRHomeController alloc] init]; self.recommentPage = vc; self.recommentPage.synchroDataBlock = ^{ @strongify(self); [self synchroData]; }; self.recommentPage.switchSelectPageBlock = ^(NSInteger selectPage) { @strongify(self); [self synchroData]; [self.scrollPageView setSelectedIndex:0 animated:YES]; }; self.recommentPage.storeDataBlock = ^{ @strongify(self); [self storeWithPage:self.recommentPage sno:1]; }; self.recommentPage.freshPageBlock = ^(NSInteger freshPageIndex) { @strongify(self); if(0 == freshPageIndex) { [self.attentionPage headerRefresh]; } else { [self.recommentPage headerRefresh]; } }; vc.type = @"1"; vc.isFreshTable = YES; vc.isNotFirstPlay = NO; childVc = vc; [self synchroData]; } } else { } return childVc; }
A页面同步数据给B页面的处理函数:
-(void)synchroData { [self updateHomeControllerWithPage:self.attentionPage sno:0]; [self updateHomeControllerWithPage:self.recommentPage sno:1]; } -(void)updateHomeControllerWithPage:(QRHomeController *)page sno:(NSInteger)sno { if(page && [page isKindOfClass:[QRHomeController class]]) { page.district_id = self.district_id; page.longStr = self.longStr; page.latiStr = self.latiStr; page.isNotFirstPlay = self.isNotFirstPlay; page.player = self.player; page.currentIndex = self.currentIndex; } }
B页面需要时,调用block通知A页面更新最新的B关注数据给B或单例。然后再使用数据:
- (void)configurationCell:(QRHomeVideoCell *)cell indexPath:(NSIndexPath *)indexPath { @weakify(self); NSMutableArray *arr1 = self.models; if (arr1.count>indexPath.row) { cell.latiStr = self.latiStr; cell.logStr = self.longStr; LCStoreModel *model = [arr1 objectAtSafeIndex:indexPath.row]; [cell setModel:model]; [cell setZanBlock:^(NSInteger ifZan) { @strongify(self); model.user_love = (ifZan == 0) ? NO : YES; }]; [cell setChangeNoBlock:^(NSInteger count) { @strongify(self); [self.currentCell.commentBtn.titleL setText:[NSString stringWithFormat:@"%ld", count]]; }]; [cell setHitAttentionBlock:^(LCStoreModel * _Nonnull model) { @strongify(self); if(model && [model isKindOfClass:[LCStoreModel class]] && !isCommonUnitEmptyArray(self.models) && model.suppliers_id > 0) { BOOL flag = NO; NSMutableArray *arr =[NSMutableArray array]; for(NSInteger n = 0; n < self.models.count; n++) { LCStoreModel *entity = self.models[n]; if(entity && [entity isKindOfClass:[LCStoreModel class]] && (entity.suppliers_id > 0) && (model.suppliers_id == entity.suppliers_id) && (entity.goods_id != model.goods_id)) { entity.user_focus = model.user_focus; NSIndexPath *indexPath1 =[NSIndexPath indexPathForRow:n inSection:0]; [arr addObject:indexPath1]; flag = YES; } } if(!isCommonUnitEmptyArray(arr)) { //为了避免重新加载时出现不需要的动画(又名“闪烁”) BOOL animationsEnabled = [UIView areAnimationsEnabled]; [UIView setAnimationsEnabled:NO]; [self.tableView reloadRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationNone]; [UIView setAnimationsEnabled:animationsEnabled]; } } if(self.type.intValue == 2){ if(self.synchroDataBlock) { self.synchroDataBlock(); } self.isFreshTable = YES; if(self.currentCell && self.player){ self.currentCell.isPause = YES; [self.player clearPlayer]; //返回关注的列表,暂停之前的播放 [self.player stopPlay]; } [self headerRefresh]; if(self.freshPageBlock) { self.freshPageBlock(1); } } else { //刷新推荐列表 if(self.freshPageBlock) { self.freshPageBlock(0); } } [self loginIMaccount]; }]; cell.changePlayBlock = ^(BOOL isPause) { @strongify(self); if(isPause) { [self.player pause]; } else { [self repeatPlayWithIsPause:YES]; } }; cell.endEditingBlock = ^{ @strongify(self); [self.view endEditing:YES]; }; } }