Files
peko-ios/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.m

883 lines
28 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// GiftComboManager.m
// YuMi
//
// Created by P on 2024/9/5.
//
// 处理连击面板逻辑
#import "GiftComboManager.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Bugly/Bugly.h>
#import "BuglyManager.h"
#import "Api+Gift.h"
#import "UserInfoModel.h"
#import "AttachmentModel.h"
#import "XPGiftCountModel.h"
#import "GiftReceiveInfoModel.h"
#import "XPMessageRemoteExtModel.h"
#import "GiftComboFlagView.h"
// 通知常量实现
NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotification";
@interface GiftComboManager ()
@property (nonatomic, assign) BOOL enableCombo;
@property (nonatomic, strong) NSMutableArray *requestQueue;
// 用来存储 GiftReceiveInfoModel 和 NSDictionary 的元数据队列
@property (nonatomic, strong) NSMutableArray *networkQueue; // 网络通信队列AttachmentModel
@property (nonatomic, strong) NSMutableArray *uiQueue; // UI动画队列GiftReceiveInfoModel
@property (nonatomic, strong) dispatch_source_t comboFlagTimer;
@property (nonatomic, strong) UIView *containerView;
// 定时器,处理请求的调度器
@property (nonatomic, strong) dispatch_source_t timer;
// 新增:后台处理队列
@property (nonatomic, strong) dispatch_queue_t backgroundQueue;
@property (nonatomic, strong) dispatch_queue_t networkProcessingQueue;
@property (nonatomic, copy) NSArray *sendGiftToUIDs;
@property (nonatomic, assign) GiftSourceType giftSourceType;
@property (nonatomic, strong) GiftInfoModel *giftInfo;
@property (nonatomic, assign) RoomSendGiftType roomSendGiftType;
@property (nonatomic, copy) NSString *roomUID;
@property (nonatomic, copy) NSString *giftNumPerTimes;
@property (nonatomic, strong) UserInfoModel *sendGiftUserInfo;
@property (nonatomic, copy) NSString *sessionID;
@property (nonatomic, strong) XPGiftCountModel *countModel;
@property (nonatomic, assign) NSInteger combo;
@property (nonatomic, assign) bool isCombing;
@property (nonatomic, copy) void (^actionCallback)(ComboActionType type);
@property (nonatomic, copy) NSString *errorMessage;
@property (nonatomic, strong) NSMutableArray<GiftComboFlagView *> *activeViews; // 用于存储最多2个活跃的动画视图
@end
@implementation GiftComboManager
#pragma mark - 单例方法
- (void)dealloc {
// 🔥 修复确保所有timer都被停止
[self forceStopAllTimers];
// 停止UI队列处理
[self stopProcessingUIQueue];
// 清空所有队列
[self clearAllQueues];
// 重置状态
self.isCombing = NO;
self.enableCombo = NO;
self.actionCallback = nil;
}
+ (instancetype)sharedManager {
static GiftComboManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
// sharedInstance.giftComboQueue = [NSMutableArray array];
sharedInstance.networkQueue = [NSMutableArray array];
sharedInstance.uiQueue = [NSMutableArray array];
sharedInstance.activeViews = [NSMutableArray array];
sharedInstance.requestQueue = [NSMutableArray array];
// 初始化后台处理队列
sharedInstance.backgroundQueue = dispatch_queue_create("com.yumi.giftcombo.background", DISPATCH_QUEUE_CONCURRENT);
sharedInstance.networkProcessingQueue = dispatch_queue_create("com.yumi.giftcombo.network", DISPATCH_QUEUE_SERIAL);
[sharedInstance startProcessingUIQueue];
});
return sharedInstance;
}
//// 添加 GiftReceiveInfoModel 和 metadata 到队列
- (void)addGiftComboWithInfo:(GiftReceiveInfoModel *)info andMetadata:(NSDictionary *)metadata {
if (info && metadata) {
// 将元数据打包成字典并添加到队列
@synchronized (self) {
NSDictionary *comboData = @{@"info": info, @"metadata": metadata};
[self.networkQueue addObject:comboData];
}
// 启动定时器
[self startProcessingQueue];
}
}
- (void)addComboFromNIMAttachment:(AttachmentModel *)attachment {
if (attachment) {
// 将元数据打包成字典并添加到队列
@synchronized (self) {
[self.networkQueue addObject:attachment];
}
// 启动定时器
[self startProcessingQueue];
}
}
// 开始连击,重置
- (void)reset {
// 🔥 修复:检查是否正在重置过程中
if (self.isCombing && self.combo == 0) {
return;
}
// 🔥 修复如果actionCallback为空延迟执行reset
if (!self.actionCallback) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self reset];
});
return;
}
// 🔥 修复确保enableCombo状态正确
if (!self.enableCombo) {
self.enableCombo = YES;
}
// 确保连击计数正确重置为 1
_combo = 1;
_errorMessage = @"";
// 验证重置后的状态
// 发送通知,让 GiftComboView 重置显示
[[NSNotificationCenter defaultCenter] postNotificationName:@"ComboCountReset" object:nil];
// 🔥 修复:确保状态正确设置后再触发回调
self.isCombing = YES;
// 检查是否应该显示连击面板 - 确保在主线程执行UI回调
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
if (self && self.actionCallback) {
self.actionCallback(ComboAction_ShowPanel);
}
}];
} else {
}
if (self.handleRoomUIChanged) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
if (self && self.handleRoomUIChanged) {
self.handleRoomUIChanged(YES);
}
}];
}
}
- (void)registerActions:(void (^)(ComboActionType))action {
_combo = 1;
_errorMessage = @"";
self.actionCallback = action;
}
// 新增:实现其他简化接口方法
- (void)activate {
self.enableCombo = YES;
}
- (void)deactivate {
self.enableCombo = NO;
}
- (BOOL)isActive {
return self.isCombing && self.enableCombo;
}
- (NSInteger)currentCount {
// 确保连击计数最少为 1
if (self.combo < 1) {
self.combo = 1;
}
return self.combo;
}
- (void)incrementCount {
self.combo += 1;
}
- (void)clear {
[self forceBoomStateReset];
// 🔥 修复确保在主线程执行UI回调并检查回调是否有效
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
if (self && self.actionCallback) {
self.actionCallback(ComboAction_RemovePanel);
}
}];
}
}
- (void)send {
[self sendGift];
}
- (NSDictionary *)stateInfo {
return [self getComboStateInfo];
}
- (BOOL)canStartCombo {
return self.enableCombo && self.giftInfo != nil && self.sendGiftToUIDs.count > 0;
}
- (void)validateState {
[self validateAndFixComboCount];
}
- (void)handleError:(NSError *)error {
self.errorMessage = error.localizedDescription;
}
- (NSString *)lastErrorMessage {
return self.errorMessage ?: @"";
}
- (void)clearError {
self.errorMessage = @"";
}
- (void)forceBoomStateReset {
// 1. 立即停止所有定时器(无条件停止)
[self forceStopAllTimers];
// 2. 清空所有队列
[self clearAllQueues];
// 3. 重置所有状态标志
self.isCombing = NO;
// 4. 重置combo计数为0
_combo = 0;
// 5. 发送通知(优先级最高,通知所有相关组件)
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kBoomStateForceResetNotification
object:nil];
});
// 6. 强制恢复UI确保底部栏和侧栏显示
if (self.handleRoomUIChanged) {
dispatch_async(dispatch_get_main_queue(), ^{
self.handleRoomUIChanged(NO);
});
}
}
// 无条件停止定时器
- (void)forceStopAllTimers {
// 停止主定时器
if (self.timer) {
dispatch_source_cancel(self.timer);
self.timer = nil;
}
// 停止UI队列定时器
if (self.comboFlagTimer) {
dispatch_source_cancel(self.comboFlagTimer);
self.comboFlagTimer = nil;
}
}
// 清空所有队列
- (void)clearAllQueues {
@synchronized (self) {
[self.requestQueue removeAllObjects];
[self.networkQueue removeAllObjects];
[self.uiQueue removeAllObjects];
}
}
- (NSInteger)loadTotalGiftNum {
return self.combo * self.countModel.giftNumber.integerValue * self.sendGiftToUIDs.count;
}
// 新增:检查连击状态是否有效
- (BOOL)isComboStateValid {
@synchronized (self) {
return self.isCombing &&
self.enableCombo &&
self.combo > 0 &&
self.giftInfo != nil &&
self.sendGiftToUIDs.count > 0;
}
}
// 新增:获取连击状态信息
- (NSDictionary *)getComboStateInfo {
@synchronized (self) {
return @{
@"isCombing": @(self.isCombing),
@"enableCombo": @(self.enableCombo),
@"combo": @(self.combo),
@"hasGiftInfo": @(self.giftInfo != nil),
@"targetCount": @(self.sendGiftToUIDs.count),
@"errorMessage": self.errorMessage ?: @""
};
}
}
// 新增:验证并修复连击计数
- (void)validateAndFixComboCount {
@synchronized (self) {
if (self.combo < 1) {
self.combo = 1;
}
if (self.combo > 1000) {
self.combo = 100;
}
}
}
#pragma mark - 处理飘屏逻辑
- (void)receiveGiftInfoForDisplayComboFlags:(GiftReceiveInfoModel *)receiveInfo
container:(UIView *)container {
self.containerView = container;
[self.uiQueue addObject:receiveInfo];
[self startProcessingUIQueue];
}
- (void)removeComboFlag {
self.containerView = nil;
[self stopProcessingQueue];
[self stopProcessingUIQueue];
}
- (void)startProcessingUIQueue {
if (self.comboFlagTimer) {
return;
}
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(timer,
DISPATCH_TIME_NOW,
0.2 * NSEC_PER_SEC,
0.01 * NSEC_PER_SEC);
@kWeakify(self);
dispatch_source_set_event_handler(timer, ^{
@kStrongify(self);
[self processGiftFlagQueue];
});
dispatch_resume(timer);
self.comboFlagTimer = timer;
}
- (void)stopProcessingUIQueue {
if (self.comboFlagTimer) {
dispatch_source_cancel(self.comboFlagTimer);
@kWeakify(self);
dispatch_source_set_cancel_handler(self.comboFlagTimer, ^{
@kStrongify(self);
self.comboFlagTimer = nil;
});
}
}
- (void)processGiftFlagQueue {
@synchronized (self) {
if (self.uiQueue.count == 0) {
return;
}
GiftReceiveInfoModel *receiveInfo = [self.uiQueue firstObject];
[self.uiQueue xpSafeRemoveObjectAtIndex:0];
dispatch_async(dispatch_get_main_queue(), ^{
[self handleGiftInfo:receiveInfo];
});
}
}
- (void)handleGiftInfo:(GiftReceiveInfoModel *)receiveInfo {
if (receiveInfo.comboCount < 1) {
// 不正常的数据,不处理
return;
}
if ([self updateExistingViewWithModel:receiveInfo]) {
// 如果更新了现有视图,就不需要创建新视图
return;
}
if (self.activeViews.count >= 2) {
GiftComboFlagView *oldestView = [self.activeViews firstObject];
[self animateRemoveView:oldestView];
}
CGFloat positionY = kGetScaleWidth(380);
CGFloat positionX = isMSRTL() ? -self.containerView.bounds.size.width : self.containerView.bounds.size.width;
GiftComboFlagView *flagView = [[GiftComboFlagView alloc] initWithFrame:CGRectMake(positionX,
positionY,
kGetScaleWidth(300),
50)];
@kWeakify(self);
@kWeakify(flagView);
[flagView setTimerEnd:^{
@kStrongify(self);
@kStrongify(flagView);
[self animateRemoveView:flagView];
}];
[flagView updateReceiveInfoModel:receiveInfo animationType:0];
[self allCurrentFlagMoveDown];
[self.containerView addSubview:flagView];
[self.activeViews insertObject:flagView atIndex:0];
[self animateView:flagView positionY:positionY];
}
- (void)allCurrentFlagMoveDown {
CGFloat positionY = kGetScaleWidth(380);
[self.activeViews enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(GiftComboFlagView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
dispatch_async(dispatch_get_main_queue(), ^{
CGRect rect = obj.frame;
rect.origin.y = positionY + idx * 50;
obj.frame = rect;
});
}];
}
- (void)animateView:(GiftComboFlagView *)flagView positionY:(CGFloat)positionY {
[UIView animateWithDuration:0.1
animations:^{
if (isMSRTL()) {
// 获取屏幕宽度
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
// 计算新的 x 坐标:屏幕宽度 - 视图宽度 - 右边距
CGFloat newX = screenWidth - 20 - kGetScaleWidth(300);
// 更新 flagView 的 frame使右边距离屏幕右边 20 像素
flagView.frame = CGRectMake(newX, positionY, kGetScaleWidth(300), 50);
} else {
flagView.frame = CGRectMake(20, positionY, kGetScaleWidth(300), 50);
}
} completion:^(BOOL finished) {
[self allCurrentFlagMoveDown];
}];
}
- (void)animateRemoveView:(GiftComboFlagView *)flagView {
[flagView removeFromSuperview];
if ([self.activeViews containsObject:flagView]) {
[self.activeViews removeObject:flagView];
flagView = nil;
}
[self allCurrentFlagMoveDown];
}
// 更新现有 View 的数据,如果存在相同的 ID
- (BOOL)updateExistingViewWithModel:(GiftReceiveInfoModel *)model {
NSInteger index = 0;
for (GiftComboFlagView *existingFlag in self.activeViews) {
if (existingFlag.superview == nil) {
continue;
}
if ([existingFlag.receiveInfo isEqual:model]) {
[self updateComboFlag:existingFlag with:model];
return YES;
}
index++;
}
return NO;
}
- (void)updateComboFlag:(GiftComboFlagView *)flagView with:(GiftReceiveInfoModel *)model {
[flagView updateReceiveInfoModel:model animationType:1];
}
// MARK: Logic is 连击面板出现后,每点击一次,就触发一次面板最后的请求,请求成功后,构造云信消息体,消息体进入队列并按 0.25s 一次的频率发送消息
#pragma mark - 管理队列
// 开始处理队列
- (void)startProcessingQueue {
if (self.timer) {
return; // 如果定时器已经在运行,直接返回
}
// 创建 GCD 定时器 - 使用后台队列避免主线程阻塞
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.backgroundQueue);
//#if DEBUG
// dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC, 0.01 * NSEC_PER_SEC);
//#else
// 优化减少间隔提高响应速度从0.25秒改为0.1秒
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC, 0.01 * NSEC_PER_SEC);
//#endif
// 定时器触发的事件处理 - 在后台队列执行
@kWeakify(self);
dispatch_source_set_event_handler(self.timer, ^{
@kStrongify(self);
if (!self) {
return;
}
[self processRequestQueue];
[self processGiftComboQueue];
});
// **立即执行一次处理方法**
[self processRequestQueue];
[self processGiftComboQueue];
// 启动定时器
dispatch_resume(self.timer);
}
// 停止处理队列
- (void)stopProcessingQueue {
if (self.timer) {
// 🔥 修复无条件停止timer不依赖队列状态
dispatch_source_cancel(self.timer);
// 设置取消回调,在资源完全释放后将 timer 置为 nil
@kWeakify(self);
dispatch_source_set_cancel_handler(self.timer, ^{
@kStrongify(self);
if (self) {
self.timer = nil;
}
});
}
}
// 处理队列中的第一个请求
- (void)processGiftComboQueue {
@synchronized (self) {
if (self.networkQueue.count > 0) {
// 获取并移除队列中的第一个网络数据
id networkData = [self.networkQueue firstObject];
[self.networkQueue xpSafeRemoveObjectAtIndex:0];
// 处理逻辑
if ([networkData isKindOfClass:[AttachmentModel class]]) {
dispatch_async(self.networkProcessingQueue, ^{
[self processGiftComboWith:(AttachmentModel *)networkData];
});
} else if ([networkData isKindOfClass:[NSDictionary class]]) {
// 处理包含info和metadata的字典
// NSDictionary *comboData = (NSDictionary *)networkData;
// GiftReceiveInfoModel *info = comboData[@"info"];
// NSDictionary *metadata = comboData[@"metadata"];
// 这里可以添加相应的处理逻辑
}
} else {
[self stopProcessingQueue];
}
}
}
// 处理元数据的实际逻辑
- (void)processGiftComboWith:(AttachmentModel *)info {
[self sendCustomMessage:info];
}
- (NSString *)loadErrorMessage {
return self.errorMessage;
}
- (void)processRequestQueue {
@synchronized (self) {
if (self.requestQueue.count > 0) {
// 获取并移除队列中的第一个元数据
NSDictionary *dic = [self.requestQueue xpSafeObjectAtIndex:0];
if (dic) {
// 优化在后台队列处理API请求避免阻塞主线程
dispatch_async(self.networkProcessingQueue, ^{
[self handleSendGift:dic];
});
[self.requestQueue removeObject:dic];
}
} else {
[self stopProcessingQueue];
}
}
}
#pragma mark - Gift meta data
// 统一配置方法替代多个save方法
- (void)configureWithGiftInfo:(GiftInfoModel *)giftInfo
targetUIDs:(NSArray *)UIDs
roomUID:(NSString *)roomUID
sessionID:(NSString *)sessionID
userInfo:(UserInfoModel *)userInfo
countModel:(XPGiftCountModel *)countModel
sourceType:(GiftSourceType)sourceType
sendType:(RoomSendGiftType)sendType
giftNum:(NSString *)giftNum {
self.giftInfo = giftInfo;
self.sendGiftToUIDs = UIDs;
self.roomUID = roomUID;
self.sessionID = sessionID;
self.sendGiftUserInfo = userInfo;
self.countModel = countModel;
self.giftSourceType = sourceType;
self.roomSendGiftType = sendType;
self.giftNumPerTimes = giftNum;
}
- (BOOL)loadEnable {
return self.enableCombo;
}
#pragma mark - XPGiftPresenter
- (void)sendGift {
NSString *allUIDs = @"";
for (NSString *item in self.sendGiftToUIDs) {
if (allUIDs.length > 0) {
allUIDs = [allUIDs stringByAppendingString:@","];
}
allUIDs = [allUIDs stringByAppendingString:item];
}
NSDictionary *dic = @{
@"targetUids":allUIDs,
@"giftNum":self.giftNumPerTimes,
@"sendType":[NSString stringWithFormat:@"%ld", GiftSendType_OnMic],
@"giftId":[NSString stringWithFormat:@"%ld", self.giftInfo.giftId],
@"giftSource":[NSString stringWithFormat:@"%ld", self.giftSourceType],
@"giftType":[NSString stringWithFormat:@"%ld", self.roomSendGiftType],
@"roomUid":self.roomUID
};
[self.requestQueue addObject:dic];
[self startProcessingQueue];
}
- (void)handleSendGift:(NSDictionary *)dic {
NSString *allUIDs = [dic objectForKey:@"targetUids"];
// NSString *giftId = [dic objectForKey:@"giftId"];
@kWeakify(self);
[Api requestSendGift:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
@kStrongify(self);
if (!self) {
return;
}
if (code == 200) {
GiftReceiveInfoModel *receive = [GiftReceiveInfoModel modelWithJSON:data.data];
receive.sourceType = [[dic objectForKey:@"giftSource"] integerValue];
receive.roomSendGiftType = [[dic objectForKey:@"giftType"] integerValue];
NSArray *array = [allUIDs componentsSeparatedByString:@","];
receive.receiveGiftNumberUser = array.count;
[self handleSendGiftSuccess:receive sourceData:data];
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning"
object:@{@"CurrentGold": receive.userPurse.diamonds,
@"Price": @(receive.gift.goldPrice * receive.giftNum * array.count),
@"isFromWinning":@(NO)}];
} else {
// 区分错误类型,优化恢复策略
if (code > 500 && code < 600) {
// 服务器错误,可能是临时问题,保持连击状态
#if DEBUG
self.errorMessage = [NSString stringWithFormat:@"服务器繁忙,请稍后重试 - %@", msg];
#else
self.errorMessage = @"Over Heat & try later";
// 使用 BuglyManager 统一上报礼物发送错误
NSString *uid = [AccountInfoStorage instance].getUid ?: @"未知用户";
NSMutableDictionary *userInfo = [@{@"targetUids": allUIDs,
@"giftNum": self.giftNumPerTimes} mutableCopy];
[userInfo addEntriesFromDictionary:dic];
[userInfo setObject:msg forKey:@"error message"];
[[BuglyManager sharedManager] reportNetworkError:uid
api:@"gift/sendV5"
code:code
userInfo:userInfo];
#endif
// 临时错误,不重置连击状态,允许用户重试
} else if (code == 31005) {
// 余额不足,需要重置连击状态
self.errorMessage = YMLocalizedString(@"XPCandyTreeInsufficientBalanceView1");
[self clear];
} else if (code == 8535) {
// VIP等级不足需要重置连击状态, 但不可能出现
self.errorMessage = @"";
[self clear];
} else {
// 其他错误,根据错误类型决定是否重置连击状态
self.errorMessage = msg;
// 对于网络错误等临时问题,保持连击状态
if (code >= 1000 && code < 2000) {
// 网络相关错误,保持连击状态
} else {
// 其他错误,重置连击状态
[self clear];
}
}
// 确保在主线程执行UI回调
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
self.actionCallback(ComboAction_Error);
}];
}
}
}
targetUids:allUIDs
giftNum:self.giftNumPerTimes
sendType:[dic objectForKey:@"sendType"]
giftId:[dic objectForKey:@"giftId"]
giftSource:[dic objectForKey:@"giftSource"]
giftType:[dic objectForKey:@"giftType"]
roomUid:[dic objectForKey:@"roomUid"]
msg:@""
uid:[AccountInfoStorage instance].getUid];
}
- (void)handleSendGiftSuccess:(GiftReceiveInfoModel *)receive
sourceData:(BaseModel *)response {
// 验证连击计数有效性
[self validateAndFixComboCount];
// 在API成功时递增combo计数
if (self.isCombing) {
self.combo += 1;
// 更新UI显示 - 确保在主线程执行UI回调
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
self.actionCallback(ComboAction_Combo_Count_Update);
}];
}
}
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:response.data];
// 确保连击计数最少为 1
NSInteger comboToSet = self.combo;
if (comboToSet < 1) {
comboToSet = 1;
}
[dic setObject:@(comboToSet) forKey:@"comboCount"];
self.sendGiftReceiveInfo = receive;
if (self.handleComboSuccess) {
self.handleComboSuccess(receive, dic);
}
// 确保在主线程执行UI回调
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
self.actionCallback(ComboAction_Update_After_Send_Success);
}];
}
}
- (void)sendCustomMessage:(AttachmentModel *)attachment {
NIMMessage *message = [[NIMMessage alloc]init];
message.setting.quickDeliveryEnabled = YES; // 开启快速投递
NIMCustomObject *object = [[NIMCustomObject alloc] init];
object.attachment = attachment;
message.messageObject = object;
UserInfoModel *userInfo = self.sendGiftUserInfo;
XPMessageRemoteExtModel *extModel = [[XPMessageRemoteExtModel alloc] init];
extModel.androidBubbleUrl = userInfo.androidBubbleUrl;
extModel.iosBubbleUrl = userInfo.iosBubbleUrl;
extModel.fromSayHelloChannel = userInfo.fromSayHelloChannel;
extModel.platformRole = userInfo.platformRole;
NSMutableDictionary *remoteExt = [NSMutableDictionary dictionaryWithObject:extModel.model2dictionary forKey:[NSString stringWithFormat:@"%ld", userInfo.uid]];
message.remoteExt = remoteExt;
//构造会话
NIMSession *session = [NIMSession session:self.sessionID type:NIMSessionTypeChatroom];
// 优化确保在主线程发送云信消息因为云信SDK可能期望在主线程调用
[self safeExecuteUIBlock:^{
NSError *error = nil;
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
if (error) {
} else {
}
}];
}
// 新增辅助方法统一处理UI回调的线程安全
- (void)safeExecuteUIBlock:(void (^)(void))uiBlock {
if (!uiBlock) return;
if ([NSThread isMainThread]) {
uiBlock();
} else {
dispatch_async(dispatch_get_main_queue(), uiBlock);
}
}
// 🔧 新增:状态通知方法实现
- (void)setUserComboState:(BOOL)isCombo forUser:(NSString *)uid {
if (!uid || uid.length == 0) {
return;
}
// 通过通知中心通知动画管理器
[[NSNotificationCenter defaultCenter] postNotificationName:@"GiftComboStateChanged"
object:nil
userInfo:@{
@"uid": uid,
@"isCombo": @(isCombo)
}];
}
- (void)clearUserComboState:(NSString *)uid {
[self setUserComboState:NO forUser:uid];
}
@end