Advanced Debug Part 2

Tiếp nối phần trước, phần này chúng ta sẽ tìm hiểu thêm về 1 số loại breakpoint khác. Các bạn có thể đọc lại phần 1 tại đây.

Exception breakpoint

Xét ví dụ sau:

@interface ViewController ()
@property (nonatomic, strong) NSArray *array;
@end

@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];

  self.array = @[];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];

  NSString *item = self.array[0];
}

@end

Chương trình trên bị crash và nhảy ra ngoài main. Như vậy rất khó để debug xem tại sao, nếu chỉ nhìn log thì không biết chỗ nào gây ra crash này.

Lúc này ta có thể sử dụng Exception breakpoint để bắt xem Exception xảy ra ở đâu và ở đoạn code nào.

Khi này ta chạy lại và thấy chương trình đã dừng ở method viewDidAppear. Từ đó ta có thể tìm ra bug gây crash trong chương trình dễ dàng hơn.

Symbolic breakpoint

Symbolic breakpoint là loại breakpoint giúp chúng ta dừng debugger lại ở symbol (method) chúng ta mong muốn.

Giả sử mình muốn tìm tất cả những chỗ thay đổi text của label. Thì mình có thể tạo một Symbolic breakpoint với symbol là [UILabel setText:].

Như vậy bất cứ chỗ nào set text của Label thì sẽ dừng lại.

Best practise

Giả sử trong chương trình của mình có một view tên là CRWWebControllerContainerView. View đó sẽ chứa một view khác bên trong. Tuy nhiên mình đang muốn tìm xem view đó add content view khi nào và ở đâu.

Khi này mình sẽ thêm một Symbolic breakpoint là [UIView addSubview:].

Tuy nhiên có rất nhiều chỗ gọi [UIView addSubview:]. Giờ mình phải tìm cách tìm đúng chỗ. Rất may là Symbolic breakpoint có hỗ trợ điều kiện. Giờ mình sẽ thêm điều kiện như sau:

[(UIView*)$arg1 isKindOfClass:[CRWWebControllerContainerView class]]

Như vậy thì trước khi breakpoint dừng lại nó sẽ check điều kiện là tham số 1 phải là view CRWWebControllerContainerView thì mới dừng lại.

Các bạn có thắc mắc tại sao mình lại dùng $arg1 ở đây không. Trong objective-c method thực chất có dạng:

ReturnType MethodName(id self, SEL _cmd, args...)

Khi nó dừng tại hàm [UIView addSubview:] thì tham số đầu tiên chính là object được gọi hàm addSubview.

Sâu 1 chút

Khi debug, chúng ta có thể dùng po $arg1 để in ra tham số thứ nhất của hàm đang dừng ở breakpoint, hoặc arg2,…, arg6 để in ra tham số từ 2 đến 6. Khi dùng arg1 thì lldb sẽ lấy địa chỉ của object ở trong thanh ghi tương ứng để in ra. Dưới đây là bảng mapping giữa argx và thanh ghi. Mình sẽ có một bài sâu về Calling Convension sẽ giúp các bạn hiểu sâu hơn và giúp chúng ta tăng skill debug hơn nữa.

argxx86-64arm64
arg1rdix0
arg2rsix1
arg3rdxx2
arg4rcxx3
arg5r8x4
arg6r9x5

Bài hôm nay chỉ đến đây thôi, các bạn đón đọc phần tiếp theo nhé.

Leave a Reply