Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclass of NSTextStorage causes crash on access link

Tags:

ios

uikit

textkit

I'm building a custom NSTextStorage class to find&match custom user input and process it inside my app. So I followed a couple of tutorials, most notably objc.io's, and created a subclass and set it's layoutManager to the same of the UITextView created via nib:

-(void)setCustomTextStorage:(NSTextStorage *)customTextStorage
{
    if (_customTextStorage != customTextStorage)
    {
        _customTextStorage = customTextStorage;
        [_customTextStorage addLayoutManager:self.textView.layoutManager];
    }
}

Then on override processEditingfor the NSTextStorage subclass and add the NSLinkAttributeName where appropriate.

BTW, The sample app is available here, make sure to checkout the custom-text-storage branch or just read the diff for this problem here

Now, when the user taps on the actual link, I get an exception that crashes the app:

2014-08-20 23:06:45.223 JSQMessages[63170:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSConcreteTextStorage attribute:atIndex:effectiveRange:]: Range or index out of bounds'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001025d2495 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001021a999e objc_exception_throw + 43
    2   CoreFoundation                      0x00000001025d22ad +[NSException raise:format:] + 205
    3   UIFoundation                        0x000000010558273f -[NSConcreteTextStorage attribute:atIndex:effectiveRange:] + 115
    4   UIKit                               0x00000001013d401b -[UITextView(LinkInteraction) _interactableItemAtPoint:] + 789
    5   UIKit                               0x00000001013d59a4 -[UITextView(LinkInteraction) willInteractWithLinkAtPoint:] + 17
    6   UIKit                               0x000000010108801b -[UITextInteractionAssistant(UITextInteractionAssistant_Internal) gestureRecognizerShouldBegin:] + 305
    7   UIKit                               0x000000010107fc7b -[UIGestureRecognizer _shouldBegin] + 1026
    8   UIKit                               0x000000010107cdfd -[UIGestureRecognizer setState:] + 183
    9   UIKit                               0x0000000100ebcd3f -[UIDelayedAction timerFired:] + 68
    10  Foundation                          0x0000000101d93e14 __NSFireTimer + 83
    11  CoreFoundation                      0x0000000102594c34 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    12  CoreFoundation                      0x00000001025947b2 __CFRunLoopDoTimer + 962
    13  CoreFoundation                      0x000000010257d7be __CFRunLoopRun + 1614
    14  CoreFoundation                      0x000000010257cd83 CFRunLoopRunSpecific + 467
    15  GraphicsServices                    0x0000000103c2ef04 GSEventRunModal + 161
    16  UIKit                               0x0000000100d56e33 UIApplicationMain + 1010
    17  JSQMessages                         0x0000000100014ea3 main + 115
    18  libdyld.dylib                       0x000000010339f5fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Which is weird, because I set up a breakpoint there and the backingStore is returning a perfectly valid NSDictionary with the attributes.

I'll gladly buy a beer to whoever will give me a hand with this maddening issue.

Note: Also reproducible on iOS 8, so I don't think it's an iOS bug

like image 309
Pierluigi Cifani Avatar asked Aug 20 '14 21:08

Pierluigi Cifani


1 Answers

Encountered with the same problem. The only solution I've found for now is to create a full stack programmatically instead of using nib:

self.textStorage = [[CustomTextStorage alloc] init];

NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[self.textStorage addLayoutManager:layoutManager];

NSTextContainer *textContainer = [[NSTextContainer alloc] init];
[layoutManager addTextContainer:textContainer];

UITextView *textView = [[UITextView alloc] initWithFrame:frame textContainer:textContainer];
textView.delegate = self;
like image 69
Sergey Alpeev Avatar answered Oct 14 '22 21:10

Sergey Alpeev