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

883 lines
28 KiB
Mathematica
Raw Normal View History

//
// GiftComboManager.m
// YuMi
//
// Created by P on 2024/9/5.
//
//
#import "GiftComboManager.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
2025-04-21 13:52:13 +08:00
#import <Bugly/Bugly.h>
#import "BuglyManager.h"
2025-04-21 13:52:13 +08:00
#import "Api+Gift.h"
#import "UserInfoModel.h"
#import "AttachmentModel.h"
2024-09-12 14:01:12 +08:00
#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; // UIGiftReceiveInfoModel
@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;
2024-09-12 14:01:12 +08:00
@property (nonatomic, strong) XPGiftCountModel *countModel;
@property (nonatomic, assign) NSInteger combo;
@property (nonatomic, assign) bool isCombing;
@property (nonatomic, copy) void (^actionCallback)(ComboActionType type);
2024-09-12 18:49:42 +08:00
@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;
}
// 🔥 actionCallbackreset
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;
2024-09-12 18:49:42 +08:00
_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 {
}
2024-12-04 21:22:38 +08:00
if (self.handleRoomUIChanged) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
if (self && self.handleRoomUIChanged) {
self.handleRoomUIChanged(YES);
}
}];
2024-12-04 21:22:38 +08:00
}
}
- (void)registerActions:(void (^)(ComboActionType))action {
2024-09-18 17:04:07 +08:00
_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. combo0
_combo = 0;
// 5.
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kBoomStateForceResetNotification
object:nil];
});
// 6. UI
2024-12-04 21:22:38 +08:00
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];
2024-12-04 21:22:38 +08:00
}
}
2024-09-12 14:01:12 +08:00
- (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];
}
2025-01-15 19:02:58 +08:00
- (void)removeComboFlag {
self.containerView = nil;
[self stopProcessingQueue];
[self stopProcessingUIQueue];
2025-01-15 19:02:58 +08:00
}
- (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 {
2024-09-12 18:49:42 +08:00
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);
2024-09-12 14:01:12 +08:00
[self animateRemoveView:flagView];
}];
[flagView updateReceiveInfoModel:receiveInfo animationType:0];
2024-09-12 14:01:12 +08:00
[self allCurrentFlagMoveDown];
[self.containerView addSubview:flagView];
2024-09-12 18:49:42 +08:00
[self.activeViews insertObject:flagView atIndex:0];
[self animateView:flagView positionY:positionY];
}
- (void)allCurrentFlagMoveDown {
2024-09-12 14:01:12 +08:00
CGFloat positionY = kGetScaleWidth(380);
2024-09-12 18:49:42 +08:00
[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);
}
2024-09-12 14:01:12 +08:00
} completion:^(BOOL finished) {
[self allCurrentFlagMoveDown];
}];
}
- (void)animateRemoveView:(GiftComboFlagView *)flagView {
[flagView removeFromSuperview];
if ([self.activeViews containsObject:flagView]) {
[self.activeViews removeObject:flagView];
flagView = nil;
}
2024-09-12 18:49:42 +08:00
[self allCurrentFlagMoveDown];
}
// View ID
- (BOOL)updateExistingViewWithModel:(GiftReceiveInfoModel *)model {
NSInteger index = 0;
for (GiftComboFlagView *existingFlag in self.activeViews) {
2024-09-12 14:01:12 +08:00
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.250.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];
2024-12-11 10:48:01 +08:00
[self processGiftComboQueue];
});
// ****
2024-12-11 10:48:01 +08:00
[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) {
2024-12-11 10:48:01 +08:00
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]]) {
// infometadata
// NSDictionary *comboData = (NSDictionary *)networkData;
// GiftReceiveInfoModel *info = comboData[@"info"];
// NSDictionary *metadata = comboData[@"metadata"];
//
}
} else {
[self stopProcessingQueue];
}
}
}
//
- (void)processGiftComboWith:(AttachmentModel *)info {
[self sendCustomMessage:info];
}
2024-09-12 18:49:42 +08:00
- (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);
2024-09-12 18:49:42 +08:00
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];
2024-12-04 21:22:38 +08:00
[[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
2024-12-06 14:38:45 +08:00
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
self.actionCallback(ComboAction_Error);
}];
2024-12-06 14:38:45 +08:00
}
}
}
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];
// APIcombo
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"];
2024-12-06 14:38:45 +08:00
self.sendGiftReceiveInfo = receive;
if (self.handleComboSuccess) {
self.handleComboSuccess(receive, dic);
}
2024-12-06 14:38:45 +08:00
// 线UI
2024-12-06 14:38:45 +08:00
if (self.actionCallback) {
@kWeakify(self);
[self safeExecuteUIBlock:^{
@kStrongify(self);
self.actionCallback(ComboAction_Update_After_Send_Success);
}];
2024-12-06 14:38:45 +08:00
}
}
- (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;
2025-01-22 21:22:58 +08:00
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