浏览代码

修复多线程刷新数据偶现的崩溃问题

Steven 2 周之前
父节点
当前提交
5d87c32666

+ 105 - 28
KulexiuForTeacher/KulexiuForTeacher/Module/TXClassRoom/View/TXFullVideo/TXFullVideoView.m

@@ -9,6 +9,7 @@
 #import "TXFullVideoView.h"
 #import "ClassroomService.h"
 #import "TXFullVideoCell.h"
+#import "KSIndexPathValidator.h"
 
 @interface TXFullVideoView ()<UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
 
@@ -22,6 +23,12 @@
 
 @property (nonatomic, assign) CGSize cellSize;
 
+@property (nonatomic, strong) dispatch_semaphore_t signalSemaphore;
+
+@property (nonatomic, strong) dispatch_semaphore_t signalQualitySemaphore;
+
+@property (nonatomic, strong) dispatch_semaphore_t signalVolumeSemaphore;
+
 @end
 
 @implementation TXFullVideoView
@@ -32,6 +39,9 @@
     if (self) {
         _viewFrame = CGRectMake(0, 0, KLandscapeWidth, KLandscapeHeight);
         [self addSubview:self.videoView];
+        _signalSemaphore = dispatch_semaphore_create(1);
+        _signalQualitySemaphore = dispatch_semaphore_create(1);
+        _signalVolumeSemaphore = dispatch_semaphore_create(1);
         [self addCancleButton];
     }
     return self;
@@ -60,15 +70,14 @@
 }
 
 - (void)showVideoList {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        MJ_LOCK(strongSelf.signalSemaphore)
         NSArray *tempArray = [ClassroomService sharedService].currentRoom.memberList;
-//        NSMutableArray *array = [NSMutableArray arrayWithArray:[ClassroomService sharedService].currentRoom.memberList];
-//        [array addObjectsFromArray:tempArray];
-//        [array addObjectsFromArray:tempArray];
-//        [array addObjectsFromArray:tempArray];
-////        [array addObjectsFromArray:tempArray];
-//        tempArray = [NSArray arrayWithArray:array];
         if (tempArray.count <= 0) {
+            MJ_UNLOCK(strongSelf.signalSemaphore)
             return;
         }
         NSSortDescriptor * des = [[NSSortDescriptor alloc] initWithKey:@"joinTime" ascending:YES];
@@ -106,64 +115,132 @@
             [sortArray removeObjectsAtIndexes:set];
         }
         [lastArray addObjectsFromArray:sortArray];
+        
+        NSArray *safeData = [lastArray copy]; // 创建不可变副本
+
         dispatch_async(dispatch_get_main_queue(), ^{
-            self.videoDataSource = [lastArray mutableCopy];
+            if (!strongSelf || !strongSelf.videoView) {
+                MJ_UNLOCK(strongSelf.signalSemaphore)
+                return;
+            }
+            
+            self.videoDataSource = [safeData mutableCopy];
             [self.videoView reloadData];
+            MJ_UNLOCK(strongSelf.signalSemaphore)
         });
     });
 }
 
 - (void)updateUserVideo:(NSString *)userId {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        for(int i=0;i < self.videoDataSource.count; i++) {
-            RoomMember *member = self.videoDataSource[i];
-            if([member.userId isEqualToString:userId]) {
-                NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
-                dispatch_async(dispatch_get_main_queue(), ^{
-                    TXFullVideoCell * cell = (TXFullVideoCell *)[self.videoView cellForItemAtIndexPath:index];
-                    if (cell) {
-                        [self.videoView reloadItemsAtIndexPaths:@[index]];
-                    }
-                });
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(strongSelf.signalSemaphore)
+        NSArray *safeDataSource = [strongSelf.videoDataSource copy];
+        NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
+        
+        [safeDataSource enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
+            if ([member.userId isEqualToString:userId]) {
+                [indexPaths addObject:[NSIndexPath indexPathForRow:idx inSection:0]];
             }
+        }];
+        
+        if (indexPaths.count == 0) {
+            MJ_UNLOCK(strongSelf.signalSemaphore)
+            return;
         }
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            if (!strongSelf) {
+                MJ_UNLOCK(strongSelf.signalSemaphore)
+                return;
+            }
+            NSArray *validIPs = [[KSIndexPathValidator validatorWithType:KSScrollViewTypeCollectionView] validateForCollectionView:self.videoView indexPaths:indexPaths];
+            if (validIPs.count) {
+                [strongSelf.videoView performBatchUpdates:^{
+                    [strongSelf.videoView reloadItemsAtIndexPaths:validIPs];
+                } completion:^(BOOL finished) {
+                    MJ_UNLOCK(strongSelf.signalSemaphore)
+                }];
+            }
+            else {
+                MJ_UNLOCK(strongSelf.signalSemaphore)
+            }
+        });
     });
 }
 
 
 - (void)updateUserQuality:(NSString *)userId netWorkingStatus:(TXNetWorkingStatus)quality {
+    
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        for(int i = 0;i < self.videoDataSource.count; i++) {
-            RoomMember *member = self.videoDataSource[i];
-            if([member.userId isEqualToString:userId]) {
-                NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(strongSelf.signalQualitySemaphore)
+        NSArray *safeDataSource = [strongSelf.videoDataSource copy];
+        
+        [safeDataSource enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
+            if ([member.userId isEqualToString:userId]) {
+                RoomMember *currentMember = [[ClassroomService sharedService].currentRoom getMember:userId];
+                NSIndexPath *index = [NSIndexPath indexPathForRow:idx inSection:0];
+                
                 dispatch_async(dispatch_get_main_queue(), ^{
+                    __strong typeof(weakSelf) strongSelf = weakSelf;
+                    if (!strongSelf) {
+                        MJ_UNLOCK(strongSelf.signalQualitySemaphore)
+                        return;
+                    }
+                    
                     TXFullVideoCell * cell = (TXFullVideoCell *)[self.videoView cellForItemAtIndexPath:index];
                     if (cell) {
                         [cell updateQuality:quality];
                     }
+                    MJ_UNLOCK(strongSelf.signalQualitySemaphore)
                 });
+                return;
             }
-        }
+        }];
+        MJ_UNLOCK(strongSelf.signalQualitySemaphore)
     });
 }
 
 - (void)updateMicStatus:(NSString *)userId volume:(NSInteger)volume {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        for(int i = 0;i < self.videoDataSource.count; i++) {
-            RoomMember *member = self.videoDataSource[i];
-            if([member.userId isEqualToString:userId]) {
+        
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(strongSelf.signalVolumeSemaphore)
+        NSArray *safeDataSource = [strongSelf.videoDataSource copy];
+        
+        [safeDataSource enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
+            if ([member.userId isEqualToString:userId]) {
                 RoomMember *currentMember = [[ClassroomService sharedService].currentRoom getMember:userId];
-
-                NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
+                NSIndexPath *index = [NSIndexPath indexPathForRow:idx inSection:0];
+                
                 dispatch_async(dispatch_get_main_queue(), ^{
+                    __strong typeof(weakSelf) strongSelf = weakSelf;
+                    if (!strongSelf) {
+                        MJ_UNLOCK(strongSelf.signalVolumeSemaphore)
+                        return;
+                    }
+                    
                     TXFullVideoCell * cell = (TXFullVideoCell *)[self.videoView cellForItemAtIndexPath:index];
                     if (cell) {
                         [cell updateUserVolume:volume isCloseMic:!currentMember.microphoneEnable];
                     }
+                    MJ_UNLOCK(strongSelf.signalVolumeSemaphore)
                 });
+                return;
             }
-        }
+        }];
+        MJ_UNLOCK(strongSelf.signalVolumeSemaphore)
     });
 }
 

+ 111 - 42
KulexiuForTeacher/KulexiuForTeacher/Module/TXClassRoom/View/VideoList/TXClassroomVideoListView.m

@@ -10,6 +10,7 @@
 #import "TXClassroomVideoListCell.h"
 #import "ClassroomService.h"
 #import "ClassMemberEmptyView.h"
+#import "KSIndexPathValidator.h"
 
 
 
@@ -51,10 +52,15 @@
 }
 
 - (void)getDataSource {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        MJ_LOCK(self.signalSemaphore);
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(self.signalSemaphore)
         NSArray *tempArray = [ClassroomService sharedService].currentRoom.memberList;
         if (tempArray.count <= 0) {
+            MJ_UNLOCK(strongSelf.signalSemaphore)
             return;
         }
         NSSortDescriptor * des = [[NSSortDescriptor alloc] initWithKey:@"joinTime" ascending:YES];
@@ -96,20 +102,29 @@
         
         // 移除掉主屏显示成员
         NSString *display = [ClassroomService sharedService].currentRoom.currentDisplayURI;
-        for (RoomMember *member in lastArray) {
+        NSMutableIndexSet *removeIndexes = [[NSMutableIndexSet alloc] init];
+        [lastArray enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
             if ([member.userId isEqualToString:display] && [ClassroomService sharedService].currentRoom.currentDisplayType != DisplayWhiteboard) {
-                [lastArray removeObject:member];
-                break;
+                [removeIndexes addIndex:idx];
+                *stop = YES;
             }
-        }
-        
+        }];
+        [lastArray removeObjectsAtIndexes:removeIndexes];
+
+        NSArray *safeData = [lastArray copy]; // 创建不可变副本
         dispatch_async(dispatch_get_main_queue(), ^{
-            self.videoDataSource = [lastArray mutableCopy];
-            NSLog(@"---------- list count %zd", lastArray.count);
-            [self.videoListTableView reloadData];
-            [self changeEmptyDisplay];
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            if (!strongSelf || !strongSelf.videoListTableView) {
+                MJ_UNLOCK(strongSelf.signalSemaphore)
+                return;
+            }
+            
+            strongSelf.videoDataSource = [safeData mutableCopy];
+            [strongSelf.videoListTableView reloadData];
+            [strongSelf changeEmptyDisplay];
+            MJ_UNLOCK(strongSelf.signalSemaphore)
         });
-        MJ_UNLOCK(self.signalSemaphore)
+
     });
 }
 
@@ -121,61 +136,115 @@
 }
 
 - (void)updateUserVideo:(NSString *)userId {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        MJ_LOCK(self.signalSemaphore)
-        for(int i=0;i < self.videoDataSource.count; i++) {
-            RoomMember *member = self.videoDataSource[i];
-            if([member.userId isEqualToString:userId]) {
-                NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
-                dispatch_async(dispatch_get_main_queue(), ^{
-                    TXClassroomVideoListCell * cell = [self.videoListTableView cellForRowAtIndexPath:index];
-                    if (cell) {
-                        [self.videoListTableView reloadRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationNone];
-                    }
-                });
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(strongSelf.signalSemaphore)
+        NSArray *safeDataSource = [strongSelf.videoDataSource copy];
+        NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
+        
+        [safeDataSource enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
+            if ([member.userId isEqualToString:userId]) {
+                [indexPaths addObject:[NSIndexPath indexPathForRow:idx inSection:0]];
             }
+        }];
+        
+        if (indexPaths.count == 0) {
+            MJ_UNLOCK(strongSelf.signalSemaphore)
+            return;
         }
-        MJ_UNLOCK(self.signalSemaphore)
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            if (!strongSelf) {
+                MJ_UNLOCK(strongSelf.signalSemaphore)
+                return;
+            }
+            NSArray *validIPs = [[KSIndexPathValidator validatorWithType:KSScrollViewTypeTableView] validateForTableView:self.videoListTableView indexPaths:indexPaths];
+            if (validIPs.count) {
+                [strongSelf.videoListTableView performBatchUpdates:^{
+                    [strongSelf.videoListTableView reloadRowsAtIndexPaths:validIPs
+                                                      withRowAnimation:UITableViewRowAnimationNone];
+                } completion:^(BOOL finished) {
+                    MJ_UNLOCK(strongSelf.signalSemaphore)
+                }];
+            }
+            else {
+                MJ_UNLOCK(strongSelf.signalSemaphore)
+            }
+        });
     });
 }
 
 - (void)updateUserQuality:(NSString *)userId netWorkingStatus:(TXNetWorkingStatus)quality {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        MJ_LOCK(self.signalQualitySemaphore)
-        for(int i = 0;i < self.videoDataSource.count; i++) {
-            RoomMember *member = self.videoDataSource[i];
-            if([member.userId isEqualToString:userId]) {
-                NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(strongSelf.signalQualitySemaphore)
+        NSArray *safeDataSource = [strongSelf.videoDataSource copy];
+        
+        [safeDataSource enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
+            if ([member.userId isEqualToString:userId]) {
+                RoomMember *currentMember = [[ClassroomService sharedService].currentRoom getMember:userId];
+                NSIndexPath *index = [NSIndexPath indexPathForRow:idx inSection:0];
+                
                 dispatch_async(dispatch_get_main_queue(), ^{
-                    TXClassroomVideoListCell * cell = [self.videoListTableView cellForRowAtIndexPath:index];
+                    __strong typeof(weakSelf) strongSelf = weakSelf;
+                    if (!strongSelf) {
+                        MJ_UNLOCK(strongSelf.signalQualitySemaphore)
+                        return;
+                    }
+                    
+                    TXClassroomVideoListCell * cell = [strongSelf.videoListTableView cellForRowAtIndexPath:index];
                     if (cell) {
                         [cell updateQuality:quality];
                     }
+                    MJ_UNLOCK(strongSelf.signalQualitySemaphore)
                 });
+                return;
             }
-        }
-        MJ_UNLOCK(self.signalQualitySemaphore)
+        }];
+        
+        MJ_UNLOCK(strongSelf.signalQualitySemaphore)
     });
 }
 
 - (void)updateMicStatus:(NSString *)userId volume:(NSInteger)volume {
+    __weak typeof(self) weakSelf = self;
     dispatch_async(self.videoListQueue, ^{
-        MJ_LOCK(self.signalVolumeSemaphore)
-        for(int i = 0;i < self.videoDataSource.count; i++) {
-            RoomMember *member = self.videoDataSource[i];
-            if([member.userId isEqualToString:userId]) {
-                RoomMember *roomMember = [[ClassroomService sharedService].currentRoom getMember:userId];
-
-                NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (!strongSelf) return;
+        
+        MJ_LOCK(strongSelf.signalVolumeSemaphore)
+        NSArray *safeDataSource = [strongSelf.videoDataSource copy];
+        
+        [safeDataSource enumerateObjectsUsingBlock:^(RoomMember *member, NSUInteger idx, BOOL *stop) {
+            if ([member.userId isEqualToString:userId]) {
+                RoomMember *currentMember = [[ClassroomService sharedService].currentRoom getMember:userId];
+                NSIndexPath *index = [NSIndexPath indexPathForRow:idx inSection:0];
+                
                 dispatch_async(dispatch_get_main_queue(), ^{
-                    TXClassroomVideoListCell * cell = [self.videoListTableView cellForRowAtIndexPath:index];
+                    __strong typeof(weakSelf) strongSelf = weakSelf;
+                    if (!strongSelf) {
+                        MJ_UNLOCK(strongSelf.signalVolumeSemaphore)
+                        return;
+                    }
+                    
+                    TXClassroomVideoListCell *cell = [strongSelf.videoListTableView cellForRowAtIndexPath:index];
                     if (cell) {
-                        [cell updateUserVolume:volume isCloseMic:!roomMember.microphoneEnable];
+                        [cell updateUserVolume:volume isCloseMic:!currentMember.microphoneEnable];
                     }
+                    MJ_UNLOCK(strongSelf.signalVolumeSemaphore)
                 });
+                return;
             }
-        }
-        MJ_UNLOCK(self.signalVolumeSemaphore)
+        }];
+        
+        MJ_UNLOCK(strongSelf.signalVolumeSemaphore)
     });
 }
 

+ 1 - 0
KulexiuForTeacher/Pods/Headers/Private/KSToolsLibrary/KSIndexPathValidator.h

@@ -0,0 +1 @@
+../../../../../../../WorkSpace/TargetModule/my-local-repo/KSToolsLibrary/KSToolsLibrary/Classes/TableView/KSIndexPathValidator.h

+ 1 - 0
KulexiuForTeacher/Pods/Headers/Public/KSToolsLibrary/KSIndexPathValidator.h

@@ -0,0 +1 @@
+../../../../../../../WorkSpace/TargetModule/my-local-repo/KSToolsLibrary/KSToolsLibrary/Classes/TableView/KSIndexPathValidator.h

文件差异内容过多而无法显示
+ 1457 - 1455
KulexiuForTeacher/Pods/Pods.xcodeproj/project.pbxproj


部分文件因为文件数量过多而无法显示