postNotificationName同步调用导致的白屏问题

本文分析了一个聊天应用中发送图片后出现白屏的问题。问题源于发送图片时触发了多次界面刷新,导致界面绘制错乱。文章详细介绍了问题的复现过程及解决方法,通过调整通知的抛出方式来避免界面刷新冲突。

项目的聊天窗口遇到一个白屏的问题:

只要发送一个图片后,再发任何消息都导致聊天窗口白屏。

出问题的代码摘要如下:

//HWChatViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
       
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadChatCollectionViewData) name:HWCHAT_VIEW_NEED_RELOAD object:nil];
}

-(void)reloadChatCollectionViewData {
    HWLog(@"111111*********");
    yoho_dispatch_execute_in_main_queue(^{
        HWLog(@"22222==========");
        [_collectionView reloadData];
        [_collectionView layoutIfNeeded];
        HWLog(@"33333+++++++++++");
        [_collectionView scrollToBottomAnimated:YES];
    });
}



//HWChatManager.m
-(void)reloadChatCollectionViewData {
    yoho_dispatch_execute_in_main_queue(^{
        HWLog(@"抛通知HWCHAT_VIEW_NEED_RELOAD");
        [[NSNotificationCenter defaultCenter] postNotificationName:HWCHAT_VIEW_NEED_RELOAD object:nil];
    });
}



//HWPhotoMediaItem

- (UIView *)mediaView {
    if (_cachedImageView == nil) {
        CGSize size = [self mediaViewDisplaySize];
        UIImageView *imageView = [[UIImageView alloc] init];
        
        NSURL *url = [NSURL URLWithString:_imageUrl];
        if ([[url.scheme lowercaseString] isEqualToString:@"http"]) {
            [imageView sd_setImageWithURL:url completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                _size = image.size;
                yoho_dispatch_execute_in_main_queue(^{
                    HWLog(@"抛通知HWCHAT_VIEW_NEED_RELOAD");
                    [[NSNotificationCenter defaultCenter] postNotificationName:HWCHAT_VIEW_NEED_RELOAD object:nil];
                });
            }];
        } else {
             //other code
        }

        //other code
    }
    
    return _cachedImageView;
}



聊天窗口发图,输出的log如下:


|[HWChatManager.m 175]: __45-[HWChatManager reloadChatCollectionViewData]_block_invoke 抛通知HWCHAT_VIEW_NEED_RELOAD
|[HWChatViewController.m 162]: -[HWChatViewController reloadChatCollectionViewData] 111111*********
|[HWChatViewController.m 164]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke 22222==========
|[HWPhotoMediaItem.m 41]: __29-[HWPhotoMediaItem mediaView]_block_invoke_2 抛通知HWCHAT_VIEW_NEED_RELOAD
|[HWChatViewController.m 162]: -[HWChatViewController reloadChatCollectionViewData] 111111*********
|[HWChatViewController.m 164]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke 22222==========
|[HWChatViewController.m 167]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke 33333+++++++++++
|[HWChatViewController.m 167]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke 33333+


从log可以看出HWChatManager抛通知HWCHAT_VIEW_NEED_RELOAD使得[HWChatViewController reloadChatCollectionViewData]被调用。
[_collectionView reloadData];因为要绘制HWPhotoMediaItem,if(_cachedImageView == nil)时又抛了一个同样的通知,再次同步调用了[HWChatViewController reloadChatCollectionViewData]。
于是[_collectionView reloadData];未完成的情况下又reloadData了一次,图片是发出去且正常显示了,但导致了界面绘制错乱,后续发消息都白屏了(为什么reloadData过程中再reloadData会错乱导致白屏,这个问题待研究).


避免错乱的解决办法是mediaView里抛通知时在异步线程抛,利用线程切换避免reloadData过程中再reloadData。
Thread 0 name: Thread 0: 0 libsystem_kernel.dylib 0x00000001fe63bc84 mach_msg2_trap + 8 (:-1) 1 libsystem_kernel.dylib 0x00000001fe64eb54 mach_msg2_internal + 80 (mach_msg.c:201) 2 libsystem_kernel.dylib 0x00000001fe64ee2c mach_msg_overwrite + 540 (mach_msg.c:0) 3 libsystem_kernel.dylib 0x00000001fe63c1c8 mach_msg + 24 (mach_msg.c:323) 4 CoreFoundation 0x00000001bf748024 __CFRunLoopServiceMachPort + 160 (CFRunLoop.c:2622) 5 CoreFoundation 0x00000001bf749250 __CFRunLoopRun + 1208 (CFRunLoop.c:3005) 6 CoreFoundation 0x00000001bf74e3ec CFRunLoopRunSpecific + 612 (CFRunLoop.c:3418) 7 GraphicsServices 0x00000001fac1335c GSEventRunModal + 164 (GSEvent.c:2196) 8 UIKitCore 0x00000001c1adb6e8 -[UIApplication _run] + 888 (UIApplication.m:3782) 9 UIKitCore 0x00000001c1adb34c UIApplicationMain + 340 (UIApplication.m:5372) 10 shandongMarket 0x000000010443ab90 main + 80 (main.m:14) 11 dyld 0x00000001dec4edec start + 2220 (dyldMain.cpp:1165) Thread 1 name: Thread 1: 0 libsystem_kernel.dylib 0x00000001fe63c7bc __ulock_wait + 8 1 libdispatch.dylib 0x00000001c6b9f89c _dlock_wait + 56 (lock.c:326) 2 libdispatch.dylib 0x00000001c6b9f650 _dispatch_thread_event_wait_slow + 56 (lock.c:558) 3 libdispatch.dylib 0x00000001c6bae714 __DISPATCH_WAIT_FOR_QUEUE__ + 368 (queue.c:1683) 4 libdispatch.dylib 0x00000001c6bae2c0 _dispatch_sync_f_slow + 148 (queue.c:1769) 5 shandongMarket 0x000000010515ddb4 -[BLYDataManager fetchValueForKey:] + 244 6 shandongMarket 0x00000001051577e4 -[BLYAnalyticsManager lastSessionUseInfo] + 196 7 shandongMarket 0x0000000105157118 -[BLYAnalyticsManager applicationDidCrashed:] + 104 8 CoreFoundation 0x00000001bf706590 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148 (CFNotificationCenter.c:661) 9 CoreFoundation 0x00000001bf7aa828 ___CFXRegistrationPost_block_invoke + 88 (CFNotificationCenter.c:175) 10 CoreFoundation 0x00000001bf78d8b8 _CFXRegistrationPost + 440 (CFNotificationCenter.c:201) 11 CoreFoundation 0x00000001bf71aafc _CFXNotificationPost + 700 (CFNotificationCenter.c:1193) 12 Foundation 0x00000001b99e5d38 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92 (NSNotification.m:518) 13 shandongMarket 0x0000000105167a18 -[BLYCrashManager didCrashAccidentHappened] + 204 14 shandongMarket 0x000000010513abdc BLYCrashHandlerCallback + 428 15 shandongMarket 0x0000000105138798 BLYBSDSignalHandlerCallback + 96 16 libsystem_platform.dylib 0x000000021f3eb214 _sigtramp + 56 (sigtramp.c:116) 17 libdispatch.dylib 0x00000001c6ba53d8 _dispatch_lane_class_dispose + 172 (queue.c:0) 18 libdispatch.dylib 0x00000001c6b9dd28 _dispatch_dispose + 208 (object.c:257) 19 libdispatch.dylib 0x00000001c6b9e650 -[OS_dispatch_queue _xref_dispose] + 56 (object.m:324) 20 HelpDesk 0x0000000106bf0c18 -[HDFMDatabaseQueue dealloc] + 36 (HDFMDatabaseQueue.m:137) 21 HelpDesk 0x0000000106ba6608 -[FLDBManager closeDB] + 80 (FLDBManager.m:105) 22 HelpDesk 0x0000000106c08b60 -[HDClient closeDB] + 40 (HDClient.m:1112) 23 HelpDesk 0x0000000106c08300 -[HDClient logout:] + 132 (HDClient.m:964) 24 HelpDesk 0x0000000106c08418 __30-[HDClient logout:completion:]_block_invoke + 32 (HDClient.m:974) 25 libdispatch.dylib 0x00000001c6b9d320 _dispatch_call_block_and_release + 32 (init.c:1518) 26 libdispatch.dylib 0x00000001c6b9eeac _dispatch_client_callout + 20 (object.m:560) 27 libdispatch.dylib 0x00000001c6ba1f8c _dispatch_queue_override_invoke + 788 (queue.c:4882) 28 libdispatch.dylib 0x00000001c6bb0944 _dispatch_root_queue_drain + 396 (queue.c:7051) 29 libdispatch.dylib 0x00000001c6bb1158 _dispatch_worker_thread2 + 164 (queue.c:7119) 30 libsystem_pthread.dylib 0x000000021f480da0 _pthread_wqthread + 228 (pthread.c:2631) 31 libsystem_pthread.dylib 0x000000021f480b7c start_wqthread + 8 (:-1)
最新发布
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值