TAG

RSS订阅

收藏本站

设为首页

当前位置:主页 > 移动开发 > IOS开发 >

-[NSString(NSExtendedStringDrawing) boundingRectWithSize:opt

发布时间:2016-11-19 15:28 类别:IOS开发

大家可能都遇到过,一些比较特殊的字符,在排版的时候,或者在渲染的时候,会抛出异常。 
当我们调试的时候,加了异常断点,就会触发断点。 
这次主要是记录一下,当出现这种异常的时候,怎样把引起这个异常的文字找出来。

我们先看一下出现这种异常时的堆栈信息
 

Crashed: com.apple.main-thread
0  libsystem_kernel.dylib         0x180846014 __pthread_kill + 8
1  libsystem_pthread.dylib        0x18090e450 pthread_kill + 112
2  libsystem_c.dylib              0x1807ba3e0 abort + 140
3  libsystem_malloc.dylib         0x18088aa38 _nano_vet_and_size_of_live + 330
4  libsystem_malloc.dylib         0x18088bdb8 nano_free + 220
5  CoreFoundation                 0x181825e8c _CFRelease + 1264
6  CoreText                       0x1844ce964 TGlyphEncoder::RunUnicodeEncoderRecursively(unsigned int, TCFRef<CTRun*>&&, __CTFont const*, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, TGlyphEncoder::ClusterMatching, bool) + 2020
7  CoreText                       0x1844cf0e0 TGlyphEncoder::AppendUnmappedCharRun(unsigned int, TCFRef<CTRun*>&, __CTFont const*, CFRange&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const&, TGlyphEncoder::ClusterMatching, bool) + 1540
8  CoreText                       0x1844ce89c TGlyphEncoder::RunUnicodeEncoderRecursively(unsigned int, TCFRef<CTRun*>&&, __CTFont const*, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, TGlyphEncoder::ClusterMatching, bool) + 1820
9  CoreText                       0x18449d7cc TGlyphEncoder::RunUnicodeEncoder(TCFRef<CTRun*>&&, __CTFont const*, CFRange, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*) + 132
10 CoreText                       0x18449b2a0 TGlyphEncoder::EncodeChars(CFRange, TAttributes const&, TGlyphList<TDeletedGlyphIndex>&, TGlyphEncoder::Fallbacks) + 1232
11 CoreText                       0x18449a9c8 TTypesetterAttrString::Initialize(__CFAttributedString const*) + 264
12 CoreText                       0x18449a78c TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) + 108
13 CoreText                       0x18449a674 CTLineCreateWithAttributedString + 56
14 UIFoundation                   0x18763eeac __NSStringDrawingEngine + 4096
15 UIFoundation                   0x18763de60 -[NSString(NSExtendedStringDrawing) boundingRectWithSize:options:attributes:context:] + 156
16 Views                          0x10016b408 -[NSString(size) sizeWithFont:forMaxSize:] (NSString+size.m:31)
17 Views                          0x100256ce0 +[TextMessageCell heightWithText:showTimeTag:] (TextMessageCell.m:143)
18 Views                          0x10034c124 +[ChatCellProvider rowHeightForTableView:withModel:] (ChatCellProvider.m:575)
19 Views                          0x10018973c -[ChatViewController tableView:heightForRowAtIndexPath:] (ChatViewController.m:237)
20 UIKit                          0x187a1a030 -[UITableView _dataSourceHeightForRowAtIndexPath:] + 108
21 UIKit                          0x1877f04d4 __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 332
22 UIKit                          0x1877afe78 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 2756
23 UIKit                          0x1877b2250 -[UITableViewRowData numberOfRows] + 108
24 UIKit                          0x1877b219c -[UITableView noteNumberOfRowsChanged] + 136
25 UIKit                          0x1877b1b88 -[UITableView reloadData] + 1708
26 Views                          0x1003fa73c -[UITableView(MJRefresh) mj_reloadData] (UIScrollView+MJRefresh.m:146)
27 Views                          0x1000c7e1c -[ChatView scrollToBottom:] (ChatView.m:299)
28 Views                          0x100188240 -[ChatViewController viewDidLoad] (ChatViewController.m:131)
29 UIKit                          0x1876d10b0 -[UIViewController loadViewIfRequired] + 1056
30 UIKit                          0x1876e8c44 -[UIViewController __viewWillAppear:] + 132
31 UIKit                          0x187871190 -[UINavigationController _startCustomTransition:] + 1136
32 UIKit                          0x187789858 -[UINavigationController _startDeferredTransitionIfNeeded:] + 676
33 UIKit                          0x1877894c0 -[UINavigationController __viewWillLayoutSubviews] + 64
34 UIKit                          0x187789424 -[UILayoutContainerView layoutSubviews] + 188
35 UIKit                          0x1876ce220 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1196
36 QuartzCore                     0x184b8e188 -[CALayer layoutSublayers] + 148
37 QuartzCore                     0x184b82e64 CA::Layer::layout_if_needed(CA::Transaction*) + 292
38 QuartzCore                     0x184b82d24 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32
39 QuartzCore                     0x184aff7ec CA::Context::commit_transaction(CA::Transaction*) + 252
40 QuartzCore                     0x184b26c58 CA::Transaction::commit() + 512
41 UIKit                          0x1876c38f0 _afterCACommitHandler + 324
42 CoreFoundation                 0x1818237dc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
43 CoreFoundation                 0x18182140c __CFRunLoopDoObservers + 372
44 CoreFoundation                 0x18182189c __CFRunLoopRun + 1024
45 CoreFoundation                 0x181750048 CFRunLoopRunSpecific + 444
46 GraphicsServices               0x1831d6198 GSEventRunModal + 180
47 UIKit                          0x18773c2fc -[UIApplication _run] + 684
48 UIKit                          0x187737034 UIApplicationMain + 208
49 Views                          0x10034c87c main (main.m:14)
50 libdispatch.dylib              0x1807345b8 (Missing)

大致可以看到, 是UILabel在 drawTextInRect时,获取某些字元信息时出异常了。 
我们的目的就是想看一下到底是什么文字引起这个问题的。

我们都知道 text 是存放在 UILabel.text 的属性上,第一印象都认为 po self.text 就可以看到罪魁祸首了。

OK, 我们看一下实际输出结果。

(lldb) po self.text
error: use of undeclared identifier 'self'
error: 1 errors parsing expression
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可以看到提示,没有找到 self ,因为当前栈帧已经去到

    frame #0: 0x0000000118914c6b libc++abi.dylib`__cxa_throw
    frame #1: 0x00000001311c782f libType1Scaler.dylib`TType1LWFNMultipleMasterHFMXTable::TType1LWFNMultipleMasterHFMXTable(TFontObjectSurrogate const&, int, short, short, int*) + 121

 ``` 
 所以提示没找到self也是很正常, 那么我们切换一下当前堆栈,把它切换到 ``` [UILabel drawRect:] ``` 这个函数里面:

 ```
 UIKit`-[UILabel drawRect:]:
    0x114d69c4b <+0>:   pushq  %rbp
    0x114d69c4c <+1>:   movq   %rsp, %rbp
    0x114d69c4f <+4>:   pushq  %rbx
    0x114d69c50 <+5>:   subq   $0x48, %rsp
    0x114d69c54 <+9>:   movq   %rdi, %rbx
    0x114d69c57 <+12>:  testq  %rbx, %rbx
    0x114d69c5a <+15>:  je     0x114d69c71               ; <+38>
    0x114d69c5c <+17>:  movq   0xa6c4ad(%rip), %rdx      ; "bounds"
    0x114d69c63 <+24>:  leaq   -0x30(%rbp), %rdi
    0x114d69c67 <+28>:  movq   %rbx, %rsi
    0x114d69c6a <+31>:  callq  0x1155c2af6               ; symbol stub for: objc_msgSend_stret
    0x114d69c6f <+36>:  jmp    0x114d69c7c               ; <+49>
    0x114d69c71 <+38>:  xorps  %xmm0, %xmm0
    0x114d69c74 <+41>:  movaps %xmm0, -0x20(%rbp)
    0x114d69c78 <+45>:  movaps %xmm0, -0x30(%rbp)
    0x114d69c7c <+49>:  movq   0xa7cdd5(%rip), %rsi      ; "drawTextInRect:"
    0x114d69c83 <+56>:  movq   -0x18(%rbp), %rax
    0x114d69c87 <+60>:  movq   %rax, 0x18(%rsp)
    0x114d69c8c <+65>:  movq   -0x20(%rbp), %rax
    0x114d69c90 <+69>:  movq   %rax, 0x10(%rsp)
    0x114d69c95 <+74>:  movq   -0x30(%rbp), %rax
    0x114d69c99 <+78>:  movq   -0x28(%rbp), %rcx
    0x114d69c9d <+82>:  movq   %rcx, 0x8(%rsp)
    0x114d69ca2 <+87>:  movq   %rax, (%rsp)
    0x114d69ca6 <+91>:  movq   %rbx, %rdi
    0x114d69ca9 <+94>:  callq  *0xaf0531(%rip)           ; (void *)0x0000000117c64800: objc_msgSend
    0x114d69caf <+100>: addq   $0x48, %rsp
    0x114d69cb3 <+104>: popq   %rbx
    0x114d69cb4 <+105>: popq   %rbp
    0x114d69cb5 <+106>: retq   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

再看看结果:

(lldb) po self.text
error: use of undeclared identifier 'self'
error: 1 errors parsing expression
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

同样,也是没有找到self标识符。但是我们从上面的汇编代码可以看到,在调用 drawTextInRext 的时候,实际上最后也是调用 objc_msgSend 这个函数。

然后我们再看一下 objc_msgSend 的函数原型:

OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
  • 1
  • 2
  • 1
  • 2

可以清楚的看到,传给objc_msgSend的第一个参数就是 self 对象。

而且从

    0x114d69c7c <+49>:  movq   0xa7cdd5(%rip), %rsi      ; "drawTextInRect:"
    0x114d69c83 <+56>:  movq   -0x18(%rbp), %rax
    0x114d69c87 <+60>:  movq   %rax, 0x18(%rsp)
    0x114d69c8c <+65>:  movq   -0x20(%rbp), %rax
    0x114d69c90 <+69>:  movq   %rax, 0x10(%rsp)
    0x114d69c95 <+74>:  movq   -0x30(%rbp), %rax
    0x114d69c99 <+78>:  movq   -0x28(%rbp), %rcx
    0x114d69c9d <+82>:  movq   %rcx, 0x8(%rsp)
    0x114d69ca2 <+87>:  movq   %rax, (%rsp)
    0x114d69ca6 <+91>:  movq   %rbx, %rdi
    0x114d69ca9 <+94>:  callq  *0xaf0531(%rip)           ; (void *)0x0000000117c64800: objc_msgSend
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里可以看到, 在 drawRect 里面,实际上是调用了 drawTextInRect,根据一些调用约定,可以判断 objc_msgSend 的第一个参数是最后压栈的,这时候我们可以猜测就是 rbx的寄存器的值。

我们可以通过 register read 指令查看当前寄存器的值。

(lldb) register read
General Purpose Registers:
       rbx = 0x00007f9f833d71e0
       rbp = 0x00007fff5096bf70
       rsp = 0x00007fff5096bf20
       r12 = 0x00007f9f83102850
       r13 = 0x00007f9f833d71e0
       r14 = 0x0000000000000020
       r15 = 0x00007f9f80f119f0
       rip = 0x0000000114d69caf  UIKit`-[UILabel drawRect:] + 100
13 registers were unavailable.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

然后我们尝试一下输出 rbx 的对象类型(如果它是一个对象的话)

(lldb) po [(id)$rbx class]
UILabel
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可以看到rbx就是我们要找的那个UILabel对象,既然找到UILabel,那么就很容易找到相应的 text 了。

(lldb) po [(id)$rbx text]
ᘡ ‍Amy��晴天冠 ୨୧˙˳⋆
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可以看到 * ᘡ ‍Amy��晴天冠 ୨୧˙˳⋆ * 是这个文本引起异常。

如果不好判断哪些寄存器是存放 self 对象的话,可以一个一个打印一下类型试试。

总结

  • 很多时候异常了,而且不在我们的函数里面,这个时候直接取 self 是取不到的。
  • 所有方法最终都调用了objc_msgSend, 调用的对象会作为第一个参数(self)传给它。
  • 可以通过查看寄存器命令 register read, 获取到self地址。
  • 也可以通过frame 指令查看当前栈的参数信息。 具体可以看看 help frame 的输出信息。

猜你会喜欢....

Copyright © 2015 www.wahenzan.com 哇!很赞 版权所有 浙ICP备14030256号-1 Power by DedeCms

浙公网安备 33010602005986号

声明:本站所有文章除标明原创外,均来自网络转载,版权归原作者所有,如果有侵犯到您的权益,请联系本站删除 网站管理员:758763728

360网站安全检测平台