html转富文本导致UICollectionView闪退问题

问题背景:
我在UICollectionViewCell中将一段html文本转成了NSMutableAttributedString富文本,然后通过UITextView显示出来,从而实现文字中的某段内容可以点击跳转url。
html转成富文本代码如下:

    NSData *data = [htmlStr dataUsingEncoding:NSUnicodeStringEncoding];
    NSMutableAttributedString *aStrContent = [[NSMutableAttributedString alloc] initWithData:data
                                                                                     options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}
                                                                          documentAttributes:nil
                                                                                       error:nil];
    if (aStrContent.length > 0) {
        [aStrContent addAttribute:NSForegroundColorAttributeName
                            value:RGBAllColor(0x5A6066)
                            range:NSMakeRange(0, aStrContent.length)];
    }
    textView.attributedText = aStrContent;

在计算cell的size时,同样也是先通过上述代码转成富文本后,再计算文本的高度。
在普通的view上通过上述代码展示一段html没有任何问题,但在我的页面滚动时,会偶发以下崩溃:

2021-12-03 16:34:46.597346+0800 GomeEShop[30821:12277281] [CollectionView] An attempt to prepare a layout while a prepareLayout call was already in progress (i.e. reentrant call) has been ignored. Please file a bug. UICollectionView instance is (; layer = ; contentOffset: {0, 1266.3333333333333}; contentSize: {390, 2770.7974196742957}; adjustedContentInset: {0, 0, 50, 0}; layout: ; dataSource: >)
2021-12-03 16:34:46.597432+0800 GomeEShop[30821:12277281] [CollectionView] An attempt to update layout information was detected while already in the process of computing the layout (i.e. reentrant call). This will result in unexpected behaviour or a crash. This may happen if a layout pass is triggered while calling out to a delegate. UICollectionViewFlowLayout instance is ()
2021-12-03 16:34:46.616407+0800 GomeEShop[30821:12277281] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 3 beyond bounds [0 .. 2]'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff2041daf2 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177e78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff2049a77f _CFThrowFormattedException + 194
3 CoreFoundation 0x00007fff2031c815 -[__NSArrayM removeAllObjects] + 0
4 UIKitCore 0x00007fff23da8a47 -[UICollectionViewFlowLayout _getSizingInfosWithExistingSizingDictionary:] + 1554
5 UIKitCore 0x00007fff23daa64b -[UICollectionViewFlowLayout _fetchItemsInfoForRect:] + 226
6 UIKitCore 0x00007fff23da36ad -[UICollectionViewFlowLayout collectionViewContentSize] + 49
7 GomeEShop 0x00000001082dc5e6 -[GMFPTGDCollectionViewLayout collectionViewContentSize] + 54
8 UIKitCore 0x00007fff23d9b983 -[UICollectionViewData _validateContentSize] + 170
9 UIKitCore 0x00007fff23d9dfc2 __45-[UICollectionViewData validateLayoutInRect:]_block_invoke.126 + 37
10 UIKitCore 0x00007fff23d9c6fc -[UICollectionViewData validateLayoutInRect:] + 405
11 UIKitCore 0x00007fff23d9fa35 -[UICollectionViewData _layoutAttributesForElementsInRect:] + 508
12 UIKitCore 0x00007fff23d9f821 -[UICollectionViewData layoutAttributesForElementsInRect:] + 87
13 UIKitCore 0x00007fff23d66d9a -[UICollectionView _indexPathForItemAtPoint:] + 201
14 UIKitCore 0x00007fff23d66c69 -[UICollectionView indexPathForItemAtPoint:] + 23
15 UIKitCore 0x00007fff240fc885 -[_UICollectionViewMultiSelectController shouldAllowSelectionExtensionAtPoint:] + 81
16 UIKitCore 0x00007fff23e3b6ef -[UIMultiSelectInteraction gestureRecognizer:shouldReceiveTouch:] + 181
17 UIKitCore 0x00007fff241b5f2d -[UIGestureRecognizer _shouldReceiveTouch:forEvent:recognizerView:] + 1387
18 UIKitCore 0x00007fff247063ea __72-[UITouchesEvent _addGestureRecognizersForView:toTouch:forContinuation:]_block_invoke + 350
19 UIKitCore 0x00007fff24705ddf __62-[UITouchesEvent _collectGestureRecognizersForView:withBlock:]_block_invoke + 502
20 UIKitCore 0x00007fff2470572f -[UITouchesEvent _collectGestureRecognizersForView:withBlock:] + 304
21 UIKitCore 0x00007fff2470625c -[UITouchesEvent _addGestureRecognizersForView:toTouch:forContinuation:] + 149
22 UIKitCore 0x00007fff24706169 -[UITouchesEvent _addGestureRecognizersForView:toTouch:] + 53
23 UIKitCore 0x00007fff247067a2 -[UITouchesEvent _addTouch:forDelayedDelivery:] + 878
24 UIKitCore 0x00007fff2471e725 _AddTouchToEventAndDetermineIfNeedsCancel + 328
25 UIKitCore 0x00007fff2471eb14 ____updateTouchesWithDigitizerEventAndDetermineIfShouldSend_block_invoke.100 + 125
26 CoreFoundation 0x00007fff203779d3 NSDICTIONARY_IS_CALLING_OUT_TO_A_BLOCK + 7
27 CoreFoundation 0x00007fff20377f3f ____NSDictionaryEnumerate_block_invoke.11 + 50
28 CoreFoundation 0x00007fff20453bad CFBasicHashApply + 117
29 CoreFoundation 0x00007fff20377af3 __NSDictionaryEnumerate + 183
30 UIKitCore 0x00007fff24723c94 __processEventQueue + 12095
31 UIKitCore 0x00007fff2471ad0f __eventFetcherSourceCallback + 104
32 CoreFoundation 0x00007fff2038c37a CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
33 CoreFoundation 0x00007fff2038c272 __CFRunLoopDoSource0 + 180
34 CoreFoundation 0x00007fff2038b7b6 __CFRunLoopDoSources0 + 346
35 CoreFoundation 0x00007fff20385f1f __CFRunLoopRun + 878
36 CoreFoundation 0x00007fff203856c6 CFRunLoopRunSpecific + 567
37 UIFoundation 0x00007fff23a48af4 -[NSHTMLReader _loadUsingWebKit] + 1847
38 UIFoundation 0x00007fff23a49a29 -[NSHTMLReader attributedString] + 22
39 UIFoundation 0x00007fff239ca839 NSReadAttributedStringFromURLOrData + 9439
40 UIFoundation 0x00007fff239c82e5 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 144
41 GomeEShop 0x0000000108355130 +[GMFPTGDPromTextCell promAttributeString:] + 240
42 GomeEShop 0x0000000108355644 +[GMFPTGDPromTextCell sizeWithModel:] + 372
43 CoreFoundation 0x00007fff204242fc invoking
+ 140
44 CoreFoundation 0x00007fff204217b2 -[NSInvocation invoke] + 303
45 CoreFoundation 0x00007fff20421a43 -[NSInvocation invokeWithTarget:] + 70
46 GomeEShop 0x00000001081c1c3b +[NSObject(GMulArgPerformSel) gm_target:performSel:arguments:] + 1019
47 GomeEShop 0x000000010844ad0c -[GMFPTGoodsDetailController collectionView:layout:sizeForItemAtIndexPath:] + 748
48 UIKitCore 0x00007fff23da8ebd -[UICollectionViewFlowLayout _getSizingInfosWithExistingSizingDictionary:] + 2696
49 UIKitCore 0x00007fff23daa64b -[UICollectionViewFlowLayout _fetchItemsInfoForRect:] + 226
50 UIKitCore 0x00007fff23da312a -[UICollectionViewFlowLayout prepareLayout] + 246
51 GomeEShop 0x00000001082dc899 -[GMFPTGDCollectionViewLayout prepareLayout] + 57
52 UIKitCore 0x00007fff23d9bb0a -[UICollectionViewData _prepareToLoadData] + 268
53 UIKitCore 0x00007fff23d9c59c -[UICollectionViewData validateLayoutInRect:] + 53
54 UIKitCore 0x00007fff23d61591 -[UICollectionView layoutSubviews] + 240
55 UIKitCore 0x00007fff24bd750c -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2924
56 QuartzCore 0x00007fff27a7718f -[CALayer layoutSublayers] + 258
57 QuartzCore 0x00007fff27a7d641 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
58 QuartzCore 0x00007fff27a89399 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
59 QuartzCore 0x00007fff279c9114 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
60 QuartzCore 0x00007fff279ffeaf _ZN2CA11Transaction6commitEv + 783
61 QuartzCore 0x00007fff27a0106b _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 79
62 CoreFoundation 0x00007fff2038b1e8 CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23
63 CoreFoundation 0x00007fff20385a67 __CFRunLoopDoObservers + 547
64 CoreFoundation 0x00007fff2038600a __CFRunLoopRun + 1113
65 CoreFoundation 0x00007fff203856c6 CFRunLoopRunSpecific + 567
66 GraphicsServices 0x00007fff2b76adb3 GSEventRunModal + 139
67 UIKitCore 0x00007fff24675187 -[UIApplication _run] + 912
68 UIKitCore 0x00007fff2467a038 UIApplicationMain + 101
69 GomeEShop 0x00000001071cc9f0 main + 112
70 libdyld.dylib 0x00007fff20256409 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 3 beyond bounds [0 .. 2]'
terminating with uncaught exception of type NSException
CoreSimulator 776.3 - Device: iPhone 12 (E58EF578-151D-40C6-ACBC-1C0D3307D6A1) - Runtime: iOS 14.2 (18B79) - DeviceType: iPhone 12
CUICatalog: Invalid asset name supplied: ''
(lldb)

开始排查问题时,我的关注点一直在collectionViewContentSize上,但一直没有找出问题,后来发现屏蔽该cell数据时不会有问题,定位到问题之后,在网上也看到了类似问题,原来是html转富文本的过程比较耗时,频繁刷新调用时会导致主线程卡死,最终导致闪退。
解决方案:
提前处理数据,在拿到接口数据初始化model时,就进行转换操作,这样只要数据不发生变化,就不会重新进行处理了。

@implementation GMMPTGDPromInfo

- (void)setPromDesc:(NSString *)promDesc {
    if ([_promDesc isEqualToString:promDesc]) {
        return;
    }
    _promDesc = promDesc;
    
    // 因为html转富文本时比较耗内存,滚动列表时多次转换处理 会导致主线程卡顿等问题,所以在model初始化时就转换后,在ui绘制时直接用
    if (GMK_Str_Not_Valid(promDesc)) {
        self.attributePromDesc = nil;
        return;
    }
    NSString *htmlStr = [NSString gmTransHTMLStringNewLineCharacter:promDesc];
    if (GMK_Str_Not_Valid(htmlStr))
    {
        self.attributePromDesc = nil;
        return;
    }
    NSData *data = [htmlStr dataUsingEncoding:NSUnicodeStringEncoding];
    NSMutableAttributedString *aStrContent = [[NSMutableAttributedString alloc] initWithData:data
                                                                                     options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}
                                                                          documentAttributes:nil
                                                                                       error:nil];
    if (aStrContent.length > 0) {
        [aStrContent addAttribute:NSForegroundColorAttributeName
                            value:RGBAllColor(0x5A6066)
                            range:NSMakeRange(0, aStrContent.length)];
    }
    self.attributePromDesc = aStrContent;
}

@end

至此问题解决,同样的道理,在UITableview中应该也会出现相同问题。

你可能感兴趣的:(html转富文本导致UICollectionView闪退问题)