drawRect 中的崩溃 - 是啥原因导致的?
Posted
技术标签:
【中文标题】drawRect 中的崩溃 - 是啥原因导致的?【英文标题】:Crash in drawRect - what causes it?drawRect 中的崩溃 - 是什么原因导致的? 【发布时间】:2012-05-25 15:46:15 【问题描述】:我的一些用户遇到了这个崩溃。
据我所知,它以某种方式连接到我的子类 NSTextView
的 -drawRect:
方法,但我看不出可能导致它的原因,并且压力测试未能消除该错误。
drawRect的代码
- (NSRange)visibleRangeOfTextView:(NSRect) rect
NSLayoutManager *layoutManager = [self
layoutManager];
NSTextContainer *textContainer = [self
textContainer];
NSRange glyphRange, characterRange;
// first transform to text container coordinates
NSPoint containerOrigin = [self textContainerOrigin];
rect.origin.x -= containerOrigin.x;
rect.origin.y -= containerOrigin.y;
// next, compute glyph range
glyphRange = [layoutManager glyphRangeForBoundingRect:rect inTextContainer:textContainer];
// finally, compute character range
characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
return characterRange;
- (NSRect)rectForCharacterRange:(NSRange)charRange
NSRect rect = [self
firstRectForCharacterRange:charRange];
rect.origin = [[self window]
convertScreenToBase:rect.origin];
rect = [self convertRect:rect fromView:nil];
if (!rect.size.width) rect.size.width = 6.0;
return rect;
- (void)drawRect:(NSRect)dirtyRect
[super drawRect:dirtyRect];
NSLog(@"Marking it");
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSRange visible = [self visibleRangeOfTextView:dirtyRect];
NSRange last = NSMakeRange(visible.location, 0); while (true)
NSRange error = [appController rangeOfMisspelledWordInString:self.string onlyInRange:visible startingAt:last.location + last.length];
last = error;
if (error.location == NSNotFound)
break;
[arr addObject:[NSValue valueWithRange:error]];
NSLog(@"Spellchecked");
[[NSColor redColor] setStroke];
CGFloat dash[] = 2.0f, 2.0f ;
// Make the text ranges and mark them
for (NSValue *val in arr)
NSRange range = [val rangeValue];
NSRect rectInTextView = [self rectForCharacterRange:range];
NSRect toDraw = rectInTextView;
NSBezierPath* aPath = [NSBezierPath bezierPath];
[aPath setLineDash:dash count:2 phase:0];
NSPoint lineStart = toDraw.origin;
lineStart.y += toDraw.size.height;
NSPoint lineEnd = lineStart;
lineEnd.x += toDraw.size.width;
[aPath moveToPoint:lineStart];
[aPath lineToPoint:lineEnd];
[aPath stroke];
;
NSLog(@"Done");
堆栈跟踪:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
objc[5751]: garbage collection is ON
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSConcreteTextStorage attribute:atIndex:longestEffectiveRange:inRange:]: Range or index out of bounds'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff91387fc6 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff8d4d7d5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff91387dfa +[NSException raise:format:arguments:] + 106
3 CoreFoundation 0x00007fff91387d84 +[NSException raise:format:] + 116
4 AppKit 0x00000001005d842c -[NSConcreteTextStorage attribute:atIndex:longestEffectiveRange:inRange:] + 131
5 AppKit 0x00000001006288ec -[NSLayoutManager(NSPrivate) _drawBackgroundForGlyphRange:atPoint:parameters:] + 910
6 AppKit 0x00000001006277a2 -[NSTextView drawRect:] + 1913
7 Skrivest√∏tte 0x000000010000b56c Skrivest√∏tte + 46444
8 AppKit 0x0000000100626e66 -[NSTextView _drawRect:clip:] + 2545
9 AppKit 0x00000001004a985d -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] + 3020
10 AppKit 0x00000001004aa34e -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] + 5821
11 AppKit 0x00000001004aa34e -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] + 5821
12 AppKit 0x00000001004a39af -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 4755
13 AppKit 0x000000010049c395 -[NSView displayIfNeeded] + 1528
14 AppKit 0x00000001004a1592 -[NSClipView _immediateScrollToPoint:] + 6533
15 AppKit 0x000000010049fb75 -[NSClipView scrollToPoint:] + 239
16 AppKit 0x000000010058f637 -[NSScrollView scrollClipView:toPoint:] + 266
17 AppKit 0x000000010058f3da -[NSClipView _scrollTo:animateScroll:flashScrollerKnobs:] + 1497
18 AppKit 0x00000001005923b7 -[NSClipView _scrollTo:animate:] + 27
19 AppKit 0x0000000100bcd5a2 __-[NSScrollView _snapRubberBand]_block_invoke_2 + 1536
20 AppKit 0x0000000100b3fc4e ____NSPeriodicInvokerScheduled_block_invoke_2 + 53
21 libdispatch.dylib 0x00007fff907b98ba _dispatch_call_block_and_release + 18
22 libdispatch.dylib 0x00007fff907bbc07 _dispatch_after_timer_callback + 16
23 libdispatch.dylib 0x00007fff907be2b6 _dispatch_source_invoke + 635
24 libdispatch.dylib 0x00007fff907baf77 _dispatch_queue_invoke + 71
25 libdispatch.dylib 0x00007fff907bb6f7 _dispatch_main_queue_callback_4CF + 257
26 CoreFoundation 0x00007fff9131d06c __CFRunLoopRun + 1724
27 CoreFoundation 0x00007fff9131c676 CFRunLoopRunSpecific + 230
28 HIToolbox 0x00007fff93ab831f RunCurrentEventLoopInMode + 277
29 HIToolbox 0x00007fff93abf5c9 ReceiveNextEventCommon + 355
30 HIToolbox 0x00007fff93abf456 BlockUntilNextEventMatchingListInMode + 62
31 AppKit 0x000000010045ff5d _DPSNextEvent + 659
32 AppKit 0x000000010045f861 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 135
33 AppKit 0x000000010045c19d -[NSApplication run] + 470
34 AppKit 0x00000001006dab88 NSApplicationMain + 867
35 Skrivest√∏tte 0x0000000100001020 Skrivest√∏tte + 4128
36 ??? 0x0000000000000002 0x0 + 2
)
【问题讨论】:
你能看看这里发生了什么吗:35 Skrivest√∏tte 0x0000000100001020 Skrivest√∏tte + 4128 对不起,这是我得到的。由于某种原因,我没有运气象征崩溃报告。 首先尝试确定是哪个使用的 NSRange 导致了异常。然后检查它的值以防出现异常。您的代码看起来不错,所以无效 NSRange 的原因可能不在它之外 tomk 我想你可能已经搞定了。我的 ios 应用程序中的类似代码有时会检测到超出 txt 视图中字符串的范围,从而导致布局管理器崩溃。我怀疑这里是一样的。真是一个奇怪的比赛条件。你为什么不把它作为一个答案,这样我就可以相信你了? 跟踪似乎表明[super drawRect:]
触发了这个(即NSTextView
本身)。你说你将它子类化......你究竟覆盖了哪些方法?您是否覆盖任何返回范围的内容,例如selectedRanges
?
【参考方案1】:
* 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*
[NSConcreteTextStorage 属性:atIndex:longestEffectiveRange:inRange:]:范围或索引超出范围'
正如 O' y 所说,这显然是一个 NSRange 异常
【讨论】:
我认为真正的原因是范围超出了文本视图中文本的长度,因此从布局管理器请求矩形会崩溃。不过,还是感谢您的建议。【参考方案2】:我认为你需要添加断言函数来检查“范围”
NSRange range = [val rangeValue];
确保范围不是NSNotFound
。
【讨论】:
虽然添加断言不会有什么坏处,但我很确定填充 arr 的代码会屏蔽掉 NSNotFound 项。以上是关于drawRect 中的崩溃 - 是啥原因导致的?的主要内容,如果未能解决你的问题,请参考以下文章
在桌面上拖动文件时可能导致 COMExceptions 的原因是啥?