lldb调试OC的若干辅助方法与注意

输出 UIView 的层级结构
输出 UIViewController 的层级结构
输出类的属性与方法列表
形如[0xAbc …]调用时如何出现方法提示 [161129更新]
lldb 如何支持 frame 类型的输出 [161204更新]

UIView的层级结构

UIView+JAlldb.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <UIKit/UIKit.h>

@interface UIView (JAlldb)

#if DEBUG

/**
* 输出view的层级结构
*/
- (void)p_recursiveView;

#endif

@end

UIView+JAlldb.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "UIView+JAlldb.h"

@implementation UIView (lldb)

#if DEBUG

- (void)p_recursiveView{

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
// 私有方法
NSLog(@"%@",[self performSelector:@selector(recursiveDescription)]);

#pragma clang diagnostic pop
}

#endif

@end

UIViewController的层级结构

UIViewController+JAlldb.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <UIKit/UIKit.h>

@interface UIViewController (JAlldb)

#if DEBUG

/**
* 输出指定vc的层级结构
*/
- (void)p_recursiveController;

#endif

@end

UIViewController+JAlldb.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "UIViewController+JAlldb.h"

@implementation UIViewController (JAlldb)

#if DEBUG

- (void)p_recursiveController{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"

// 私有方法
NSLog(@"%@",[self performSelector:@selector(_printHierarchy)]);

#pragma clang diagnostic pop
}

#endif

@end

类的属性与方法列表

NSObject+JAlldb.h

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
#import <Foundation/Foundation.h>

@interface NSObject (JAlldb)


/**
属性列表

@param recursive 是否递归
@return 属性列表
*/
- (NSArray *)p_propertyList:(BOOL)recursive;

/**
变量列表

@param recursive 是否递归
@return 变量列表
*/
- (NSArray *)p_ivarList:(BOOL)recursive;

/**
* 方法列表
*
* @param recursive 是否递归
*/
- (NSArray *)p_methodList:(BOOL)recursive;


/**
清空缓存列表
*/
- (void)p_cleanCacheList;

@end

NSObject+JAlldb.m

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#import "NSObject+JAlldb.h"
#import <objc/message.h>

@implementation NSObject (JAlldb)

const void* propertiesKey = "com.coder.lldb-exclusive.propertiesKey";
const void* ivarKey = "com.coder.lldb-exclusive.ivarKey";
const void* methodKey = "com.coder.lldb-exclusive.methodKey";

- (NSArray *)p_propertyList:(BOOL)recursive {

NSArray *glist = objc_getAssociatedObject([self class], propertiesKey);

return glist == nil ? ^{

unsigned int count = 0;
NSMutableArray *plistM = [NSMutableArray arrayWithCapacity:count];

Class cls = [self class];
do {
objc_property_t *list = class_copyPropertyList(cls, &count);
for (int i = 0; i < count; ++i) {
objc_property_t pty = list[i];
const char *pname = property_getName(pty);
[plistM addObject:[NSString stringWithUTF8String:pname]];
}
free(list);
cls = [cls superclass];
} while (cls && recursive);
objc_setAssociatedObject([self class],propertiesKey, plistM, OBJC_ASSOCIATION_COPY_NONATOMIC);
NSLog(@"Found %ld properties on %@",plistM.count,[self class]);
return plistM.copy;

}() : glist;
}

- (NSArray *)p_ivarList:(BOOL)recursive{

NSArray *glist = objc_getAssociatedObject([self class], ivarKey);

return glist == nil ? ^{

unsigned int count = 0;
NSMutableArray *plistM = [NSMutableArray arrayWithCapacity:count];

Class cls = [self class];
do {
Ivar *list = class_copyIvarList(cls, &count);
for (int i = 0; i < count; ++i) {
Ivar ity = list[i];
const char *iname = ivar_getName(ity);
[plistM addObject:[NSString stringWithUTF8String:iname]];
}
free(list);
cls = [cls superclass];
} while (cls && recursive);

NSLog(@"Found %ld ivar on %@",plistM.count,[self class]);
objc_setAssociatedObject([self class],ivarKey, plistM, OBJC_ASSOCIATION_COPY_NONATOMIC);
return plistM.copy;

}() : glist;
}

- (NSArray *)p_methodList:(BOOL)recursive {

NSArray *glist = objc_getAssociatedObject([self class], methodKey);

return glist == nil ? ^{

unsigned int methodCount = 0;
NSMutableArray *plistM = [NSMutableArray arrayWithCapacity:methodCount];

Class cls = [self class];
do {
Method *methods = class_copyMethodList(cls, &methodCount);

for (unsigned int i = 0; i < methodCount; i++) {
Method method = methods[i];

/*
printf("\t'%s'|'%s' of encoding '%s'\n",
class_getName(cls),
sel_getName(method_getName(method)),
method_getTypeEncoding(method));
*/
[plistM addObject:[NSString stringWithUTF8String:sel_getName(method_getName(method))]];
}
free(methods);
cls = [cls superclass];
}while (cls && recursive);
printf("Found %d methods on '%s'\n", methodCount, class_getName([self class]));
objc_setAssociatedObject([self class],ivarKey, plistM, OBJC_ASSOCIATION_COPY_NONATOMIC);

return plistM.copy;

}() : glist;



}

- (void)p_cleanCacheList {
objc_removeAssociatedObjects([self class]);
}

@end

[0xAbc …]调用如何出现方法提示

类地址前加类型强转

1
2
(lldb) po [(UIView *)0x117e09e80 backgroundColor] 
UIExtendedSRGBColorSpace 1 1 1 1

lldb如何支持frame类型的输出

1
2
3
$ touch ~/.lldbinit
$ echo display @import UIKit >> ~/.lldbinit
$ echo target stop-hook add -o \”target stop-hook disable\” >> ~/.lldbinit

参考