Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my app crash when backgrounding when using [NSAttributedString initWithData]

Tags:

ios

I have a viewController that manages a UICollectionView. I have a helper method that is called from cellForItemAtIndexPath that provides an NSAttributedString for a label in the cell. The helper method formats an NSAttributedString from an html string. The app will crash when moving to the background, but only if the indexPath.item is greater than 1. In other words, I can exit the app without crashing from the first or second cell, but crash consistently on the third, forth, ... cell.

Here are my helper method and stack trace. Any idea why I am crashing on exiting the app?

#pragma mark - === Utility Methods === -

- (NSAttributedString *)stepDescriptionStringForIndexPath:(NSIndexPath *)indexPath {

    NSString *headerString;
    NSString *htmlString;
    NSString *categoryString = [NSString stringWithFormat:@"Category: %@", self.knot.category.categoryName];
    NSString *abokString = [NSString stringWithFormat:@"ABOK #: %@", self.knot.abokNumber];
    NSMutableString *activitiesString = [NSMutableString stringWithCapacity:10];
    [activitiesString appendString:@"Activities: "];

    // build a string of activities to append to the description html
    NSArray *activities = [self.knot.activities allObjects];
    if ([activities count] > 0) {
        int counter = 1;
        for (Activity *activity in activities) {
            [activitiesString appendString:activity.activityName];
            if (counter < [activities count]) {
                [activitiesString appendString:@", "];
            }
            counter ++;
        }
    }

    // build an HTML string by concatinating the activities to the step description
    // and add the header string
    if(indexPath.item > 0){
        Step *step = (Step *)self.steps[indexPath.item - 1];
        headerString = [NSString stringWithFormat:@"Step %ld of %lu", (long)indexPath.item, (unsigned long)[self.steps count]];
        htmlString =[NSString stringWithFormat:@"<p>%@</p>%@", headerString, step.stepDescription];
    } else {
        headerString = @"Overview";
        htmlString = [NSString stringWithFormat:@"<p>%@</p>%@<p>%@</br>%@</br>%@</p>", headerString, self.knot.knotDescription, categoryString, abokString, activitiesString];

    }

    // convert the html string to an attributed string
    NSMutableAttributedString *attrStringFromHTML = [[NSMutableAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
                                                                                            options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                                                                                      NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]}
                                                                                 documentAttributes:nil
                                                                                              error:nil];

    // set the font for the body
    NSRange totalRange;
    totalRange.location = 0;
    totalRange.length = attrStringFromHTML.length;
    [attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:totalRange];

    // set the font for the header
    NSString *temp = [attrStringFromHTML string];

    NSRange headerRange = [temp rangeOfString:headerString];
    NSRange categoryRange = [temp rangeOfString:categoryString];
    NSRange abokRange = [temp rangeOfString:abokString];
    NSRange activitiesRange = [temp rangeOfString:activitiesString];

    [attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:18] range:headerRange];
    //set the font for the activities paragraph
    if(indexPath.item == 1){

        [attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:categoryRange];
        [attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:abokRange];
        [attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:activitiesRange];


    }
    return attrStringFromHTML;
}
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unexpected start state'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001131aad85 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000112c1edeb objc_exception_throw + 48
    2   CoreFoundation                      0x00000001131aabea +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x0000000110b96e1e -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 169
    4   UIKit                               0x00000001113a7d4e _prepareForCAFlush + 256
    5   UIKit                               0x00000001113b40b4 _beforeCACommitHandler + 12
    6   CoreFoundation                      0x00000001130cfc37 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    7   CoreFoundation                      0x00000001130cfba7 __CFRunLoopDoObservers + 391
    8   CoreFoundation                      0x00000001130c511c CFRunLoopRunSpecific + 524
    9   UIFoundation                        0x000000011a697a7a -[NSHTMLReader _loadUsingWebKit] + 2093
    10  UIFoundation                        0x000000011a698e74 -[NSHTMLReader attributedString] + 22
    11  UIFoundation                        0x000000011a6323c0 _NSReadAttributedStringFromURLOrData + 5623
    12  UIFoundation                        0x000000011a630d34 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 115
    13  WhatKnotToDo                        0x000000010e84d3ac -[CSC_iPad_KnotDetailViewController stepDescriptionStringForIndexPath:] + 2476
    14  WhatKnotToDo                        0x000000010e84c31d -[CSC_iPad_KnotDetailViewController collectionView:cellForItemAtIndexPath:] + 477
    15  UIKit                               0x0000000111bff08f -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:] + 483
    16  UIKit                               0x0000000111c02d96 -[UICollectionView _updateVisibleCellsNow:] + 4988
    17  UIKit                               0x0000000111c07575 -[UICollectionView layoutSubviews] + 258
    18  UIKit                               0x0000000111442980 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 703
    19  QuartzCore                          0x0000000112af6c00 -[CALayer layoutSublayers] + 146
    20  QuartzCore                          0x0000000112aeb08e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
    21  QuartzCore                          0x0000000112aeaf0c _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
    22  QuartzCore                          0x0000000112adf3c9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 277
    23  QuartzCore                          0x0000000112b0d086 _ZN2CA11Transaction6commitEv + 486
    24  UIKit                               0x0000000111394a0b __65-[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:]_block_invoke2222 + 601
    25  UIKit                               0x0000000111395201 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke2243 + 131
    26  FrontBoardServices                  0x00000001153e3039 -[FBSSceneSnapshotAction _finishAllRequests] + 65
    27  FrontBoardServices                  0x00000001153e2de3 -[FBSSceneSnapshotAction executeRequestsWithHandler:completionHandler:expirationHandler:] + 218
    28  UIKit                               0x0000000111395024 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke + 305
    29  UIKit                               0x0000000111394592 -[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:] + 1138
    30  UIKit                               0x0000000111394eb2 -[UIApplication _performSnapshotsWithAction:forScene:completion:] + 629
    31  UIKit                               0x0000000111394bbc -[UIApplication _handleSnapshotAction:forScene:completion:] + 153
    32  UIKit                               0x0000000111390a8f __102-[UIApplication _handleApplicationDeactivationWithScene:shouldForceExit:transitionContext:completion:]_block_invoke1993 + 290
    33  UIKit                               0x0000000111390657 __102-[UIApplication _handleApplicationDeactivationWithScene:shouldForceExit:transitionContext:completion:]_block_invoke1979 + 1258
    34  UIKit                               0x0000000111393f62 _runAfterCACommitDeferredBlocks + 317
    35  UIKit                               0x00000001113a7e4c _cleanUpAfterCAFlushAndRunDeferredBlocks + 95
    36  UIKit                               0x00000001113b4147 _afterCACommitHandler + 90
    37  CoreFoundation                      0x00000001130cfc37 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    38  CoreFoundation                      0x00000001130cfba7 __CFRunLoopDoObservers + 391
    39  CoreFoundation                      0x00000001130c57fb __CFRunLoopRun + 1147
    40  CoreFoundation                      0x00000001130c50f8 CFRunLoopRunSpecific + 488
    41  GraphicsServices                    0x0000000115203ad2 GSEventRunModal + 161
    42  UIKit                               0x0000000111387f09 UIApplicationMain + 171
    43  WhatKnotToDo                        0x000000010e820b7f main + 111
    44  libdyld.dylib                       0x000000011396592d start + 1
    45  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

like image 876
Alpinista Avatar asked Aug 02 '16 22:08

Alpinista


1 Answers

I've come across this issue too, after a few hours, i've found a solution for this one.

You'll just need to wrap the code for converting the NSAttributedString into dispatch_async.

For example:

   DispatchQueue.MainQueue.DispatchAsync(() =>
        {
            var encodingData = ((NSString)html).Encode(NSStringEncoding.Unicode, true);
            NSAttributedString data = new NSAttributedString(
            encodingData,
            new NSAttributedStringDocumentAttributes()
            {
                DocumentType = NSDocumentType.HTML,

            }, ref error);
        });

I'm using Xamarin, so these are C# code, but i believe they're similar in Swift and Obj C.

Look like when the system is making transition between pages (view controller), it will try to prevent any heavy task running on UI Thread. Which cause this issue.

like image 172
Huy.Vu Avatar answered Nov 02 '22 06:11

Huy.Vu