21

I want to trace when something changes the size of self.view. What's the correct format?

(lldb) po self.view
(UIView *) $1 = 0x0a8aba20 <UIView: 0xa8aba20; frame = (0 0; 480 864); autoresize = W+TM+BM; layer = <CALayer: 0xa8aba50>>
(lldb) watch set variable self.view.frame.size.width
error: "self" is a pointer and . was used to attempt to access "view". Did you mean "self->view.frame.size.width"?
(lldb) watch set variable self->view
error: "view" is not a member of "(PlayViewController *) self"
(lldb) watch set variable self->view.frame.size.width
error: "view" is not a member of "(PlayViewController *) self"

I've tried the documentation and other lldb watchpoint questions but can't find anything for this specific case.

Thanks for your help.

DenverCoder9
  • 3,635
  • 3
  • 31
  • 57

2 Answers2

75

The view controller references its view from its _view instance variable.

The view doesn't store its frame directly. It just returns its layer's `frame'.

The view references its layer from its _layer instance variable.

The layer doesn't store the frame either. It computes its frame from its bounds, position, anchorPoint, and transform. The size is part of bounds.

The layer doesn't store its bounds directly in an instance variable. Instead, its layer instance variable references an instance of a private C++ class, CA::Layer. The member layout of this class is undocumented.

In other words, you can go self->_view->_layer->layer to get to the CA::Layer instance, but then you're stuck because you don't know where in the CA::Layer to find the bounds.

So, trying to use a watchpoint to detect changes to the view's size is rather difficult.

It is easier to put a breakpoint on -[CALayer setBounds:].

On the simulator

Remember to use the layer address in the breakpoint condition, not the view address.

(lldb) po self.view
(UIView *) $1 = 0x0a034690 <UIView: 0xa034690; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0xa034780>>
(lldb) break set -F '-[CALayer setBounds:]' -c '((int*)$esp)[1] == 0xa034780'
Breakpoint created: 2: name = '-[CALayer setBounds:]', locations = 1, resolved = 1

When the breakpoint is hit, the CALayer instance is referenced by ((int *)$esp)[1], and the new bounds is *(CGRect *)($esp+12):

(lldb) po ((int*)$esp)[1]
(int) $8 = 167987072 <CALayer:0xa034780; position = CGPoint (384 480); bounds = CGRect (0 0; 768 1004); delegate = <UIView: 0xa034690; frame = (0 -22; 768 1004); autoresize = W+H; layer = <CALayer: 0xa034780>>; sublayers = (<CALayer: 0xa033010>); backgroundColor = <CGColor 0xa034960> [<CGColorSpace 0xa02b3b0> (kCGColorSpaceDeviceRGB)] ( 1 1 1 1 )>
(lldb) p *(CGRect*)($esp+12)
(CGRect) $9 = origin=(x=0, y=0) size=(width=768, height=960)
(lldb) finish
(lldb) po 0xa034780
(int) $10 = 167987072 <CALayer:0xa034780; position = CGPoint (384 480); bounds = CGRect (0 0; 768 960); delegate = <UIView: 0xa034690; frame = (0 0; 768 960); autoresize = W+H; layer = <CALayer: 0xa034780>>; sublayers = (<CALayer: 0xa033010>); backgroundColor = <CGColor 0xa034960> [<CGColorSpace 0xa02b3b0> (kCGColorSpaceDeviceRGB)] ( 1 1 1 1 )>

On the device

Remember to use the layer address in the breakpoint condition, not the view address.

(lldb) po self.view
(UIView *) $0 = 0x1f031a10 <UIView: 0x1f031a10; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0x1f031b00>>
(lldb) break set -F '-[CALayer setBounds:]' -c '$r0 == 0x1f031b00'
Breakpoint created: 2: name = '-[CALayer setBounds:]', locations = 1, resolved = 1

When the breakpoint is hit, the CALayer instance is referenced by $r0, the new X origin is in $r2, the new Y origin is in $r3, and the new size is *(CGSize *)$sp:

(lldb) po $r0
(unsigned int) $7 = 520297216 <CALayer:0x1f031b00; position = CGPoint (384 480); bounds = CGRect (0 0; 768 1004); delegate = <UIView: 0x1f031a10; frame = (0 -22; 768 1004); autoresize = W+H; layer = <CALayer: 0x1f031b00>>; sublayers = (<CALayer: 0x1f030840>); backgroundColor = <CGColor 0x1f031ce0> [<CGColorSpace 0x1e530ad0> (kCGColorSpaceDeviceRGB)] ( 1 1 1 1 )>
(lldb) p/f $r2
(unsigned int) $14 = 0
(lldb) p/f $r3
(unsigned int) $15 = 0
(lldb) p *(CGSize *)$sp
(CGSize) $16 = (width=768, height=960)
(lldb) finish
(lldb) po 0x1f031b00
(int) $17 = 520297216 <CALayer:0x1f031b00; position = CGPoint (384 480); bounds = CGRect (0 0; 768 960); delegate = <UIView: 0x1f031a10; frame = (0 0; 768 960); autoresize = W+H; layer = <CALayer: 0x1f031b00>>; sublayers = (<CALayer: 0x1f030840>); backgroundColor = <CGColor 0x1f031ce0> [<CGColorSpace 0x1e530ad0> (kCGColorSpaceDeviceRGB)] ( 1 1 1 1 )>
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • 2
    On ARM64 the registers are `$x0`, `$x2`, etc. – bcattle Jan 08 '15 at 01:01
  • 1
    running on MBP 64-bits with same command `break set -F '-[CALayer setBounds:]' -c '((int*)$esp)[1] == 0x7fe6e3098000'`, I'm getting this error: `Stopped due to an error evaluating condition of breakpoint 5.1: "((int*)$esp)[1] == 0x7fe6e3098000" Couldn't execute expression: Supposed to interpret, but failed: Interpreter couldn't read from memory` – ishahak Mar 29 '16 at 02:49
  • great with the `$rdi`version from JAL (see bellow) – tontonCD Jul 29 '21 at 14:57
4

On 64 bit simulators the break command should be:

break set -F '-[CALayer setBounds:]' -c '$rdi == 0x...'
JAL
  • 41,701
  • 23
  • 172
  • 300
user8030
  • 123
  • 4
  • That saved me, replace the whole `((int *)$esp)[1]` with `$rdi`, then verify with `(lldb) po $rdi`. Howerer I didn't found for `(lldb) po *(CGRect*)($rdi+???)`, do you have it? – tontonCD Jul 29 '21 at 14:50