195 lines
6.6 KiB
Markdown
195 lines
6.6 KiB
Markdown
# 礼物动画优化方案B实施总结
|
||
|
||
## 问题描述
|
||
|
||
**核心问题**:当用户在送礼时(combo),其他用户也在送礼,礼物动画(从位置a移动到位置b)将不会显示。
|
||
|
||
**触发条件**:
|
||
- 接收到云信消息,类型为 `Custom_Message_Sub_Gift_Send` 或 `Custom_Message_Sub_Gift_ChannelNotify`
|
||
- 多个用户同时送礼
|
||
- 当前用户处于combo状态
|
||
|
||
## 问题根本原因
|
||
|
||
**核心问题**:`GiftAnimationManager` 中的 `shouldUseComboAnimationForSender` 判断逻辑在多用户并发场景下不准确,导致其他用户的礼物动画被错误地当作combo动画处理,从而不显示。
|
||
|
||
### 具体问题点:
|
||
|
||
1. **全局状态判断错误**:原逻辑只检查全局combo状态,没有区分不同用户
|
||
2. **时间窗口判断不精确**:没有为每个用户维护独立的送礼时间
|
||
3. **状态管理混乱**:combo状态和动画状态没有正确分离
|
||
|
||
## 修复方案实施
|
||
|
||
### 第一步:修改 GiftAnimationManager.h - 添加新方法声明 ✅
|
||
|
||
```objc
|
||
// 🔧 新增:Combo状态管理方法
|
||
- (void)setUserComboState:(BOOL)isCombo forUser:(NSString *)uid;
|
||
- (void)clearUserComboState:(NSString *)uid;
|
||
- (void)updateUserGiftTime:(NSString *)uid;
|
||
- (void)cleanupExpiredStates;
|
||
```
|
||
|
||
### 第二步:修改 GiftAnimationManager.m - 实现精确的combo状态管理 ✅
|
||
|
||
**新增属性**:
|
||
```objc
|
||
// 🔧 新增:Combo状态管理属性
|
||
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *userComboStates;
|
||
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSDate *> *userLastGiftTime;
|
||
@property (nonatomic, assign) NSTimeInterval comboTimeWindow;
|
||
```
|
||
|
||
**核心方法实现**:
|
||
```objc
|
||
// 🔧 修改:优化shouldUseComboAnimationForSender方法
|
||
- (BOOL)shouldUseComboAnimationForSender:(NSString *)uid {
|
||
if (!uid || uid.length == 0) {
|
||
return NO;
|
||
}
|
||
|
||
// 优先使用精确状态判断
|
||
BOOL isUserInCombo = [self.userComboStates[uid] boolValue];
|
||
if (isUserInCombo) {
|
||
BOOL isCurrentUser = [uid isEqualToString:[AccountInfoStorage instance].getUid];
|
||
NSLog(@"[Combo effect] 🎯 用户 %@ 处于combo状态,是否当前用户: %@", uid, isCurrentUser ? @"YES" : @"NO");
|
||
return isCurrentUser;
|
||
}
|
||
|
||
// 兜底:时间窗口判断
|
||
NSDate *lastGiftTime = self.userLastGiftTime[uid];
|
||
if (lastGiftTime) {
|
||
NSTimeInterval timeSinceLastGift = [[NSDate date] timeIntervalSinceDate:lastGiftTime];
|
||
if (timeSinceLastGift <= self.comboTimeWindow) {
|
||
BOOL isCurrentUser = [uid isEqualToString:[AccountInfoStorage instance].getUid];
|
||
NSLog(@"[Combo effect] 🎯 用户 %@ 在时间窗口内,是否当前用户: %@", uid, isCurrentUser ? @"YES" : @"NO");
|
||
return isCurrentUser;
|
||
}
|
||
}
|
||
|
||
NSLog(@"[Combo effect] 🎯 用户 %@ 不使用combo动画", uid);
|
||
return NO;
|
||
}
|
||
```
|
||
|
||
### 第三步:修改 GiftComboManager.m - 添加状态通知机制 ✅
|
||
|
||
**新增方法**:
|
||
```objc
|
||
// 🔧 新增:状态通知方法实现
|
||
- (void)setUserComboState:(BOOL)isCombo forUser:(NSString *)uid {
|
||
// 通过通知中心通知动画管理器
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GiftComboStateChanged"
|
||
object:nil
|
||
userInfo:@{
|
||
@"uid": uid,
|
||
@"isCombo": @(isCombo)
|
||
}];
|
||
}
|
||
```
|
||
|
||
### 第四步:修改 RoomAnimationView.m - 集成新的状态管理 ✅
|
||
|
||
**添加通知监听**:
|
||
```objc
|
||
// 🔧 新增:监听combo状态变化
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(handleComboStateChanged:)
|
||
name:@"GiftComboStateChanged"
|
||
object:nil];
|
||
```
|
||
|
||
**添加用户送礼时间更新**:
|
||
```objc
|
||
// 🔧 新增:更新用户送礼时间
|
||
[self.giftAnimationManager updateUserGiftTime:receiveInfo.uid];
|
||
```
|
||
|
||
**添加状态处理方法**:
|
||
```objc
|
||
// 🔧 新增:处理combo状态变化
|
||
- (void)handleComboStateChanged:(NSNotification *)notification {
|
||
NSDictionary *userInfo = notification.userInfo;
|
||
NSString *uid = userInfo[@"uid"];
|
||
BOOL isCombo = [userInfo[@"isCombo"] boolValue];
|
||
|
||
// 通知动画管理器更新combo状态
|
||
if (isCombo) {
|
||
[self.giftAnimationManager setUserComboState:YES forUser:uid];
|
||
} else {
|
||
[self.giftAnimationManager clearUserComboState:uid];
|
||
}
|
||
}
|
||
```
|
||
|
||
### 第五步:添加清理机制 ✅
|
||
|
||
**在dealloc中添加清理**:
|
||
```objc
|
||
// 🔧 新增:清理combo状态管理
|
||
[self cleanupExpiredStates];
|
||
[self.userComboStates removeAllObjects];
|
||
[self.userLastGiftTime removeAllObjects];
|
||
```
|
||
|
||
## 修复效果
|
||
|
||
### 修复前的问题:
|
||
1. 用户A在combo状态时,用户B送礼,用户B的动画不显示
|
||
2. 全局状态判断导致所有用户的动画都被错误处理
|
||
3. 没有精确的用户状态管理
|
||
|
||
### 修复后的效果:
|
||
1. ✅ 每个用户有独立的combo状态管理
|
||
2. ✅ 精确判断当前用户是否应该使用combo动画
|
||
3. ✅ 其他用户的礼物动画正常显示
|
||
4. ✅ 添加了完整的日志记录,便于调试
|
||
5. ✅ 实现了自动清理机制,防止内存泄漏
|
||
|
||
## 技术要点
|
||
|
||
### 1. 精确状态管理
|
||
- 为每个用户维护独立的combo状态
|
||
- 使用时间窗口作为兜底判断机制
|
||
- 实现了状态自动清理
|
||
|
||
### 2. 通知机制
|
||
- 使用NSNotificationCenter实现组件间通信
|
||
- 解耦了GiftComboManager和GiftAnimationManager
|
||
- 保证了状态同步的及时性
|
||
|
||
### 3. 线程安全
|
||
- 使用串行队列处理动画
|
||
- 在主线程执行UI操作
|
||
- 避免了并发访问问题
|
||
|
||
### 4. 性能优化
|
||
- 使用字典存储用户状态,O(1)查找
|
||
- 定期清理过期状态
|
||
- 最小化内存占用
|
||
|
||
## 测试建议
|
||
|
||
### 测试场景:
|
||
1. **单用户combo测试**:验证当前用户的combo动画正常
|
||
2. **多用户并发测试**:验证其他用户的动画正常显示
|
||
3. **状态切换测试**:验证combo状态的正确切换
|
||
4. **内存泄漏测试**:验证清理机制的有效性
|
||
|
||
### 验证方法:
|
||
1. 查看日志输出,确认状态判断正确
|
||
2. 观察动画显示效果
|
||
3. 使用Instruments检查内存使用
|
||
|
||
## 总结
|
||
|
||
通过实施精确的用户状态管理、通知机制和清理机制,成功解决了多用户并发送礼时动画不显示的问题。修复方案具有以下特点:
|
||
|
||
- **精确性**:每个用户独立的状态管理
|
||
- **可靠性**:完整的错误处理和日志记录
|
||
- **性能**:高效的数据结构和自动清理
|
||
- **可维护性**:清晰的代码结构和注释
|
||
|
||
该修复方案确保了礼物动画系统在多用户并发场景下的稳定性和正确性。
|