前言
HSD(HttpServerDebug) 实现了类似 Xcode 中的视图调试功能,如下图所示。在 HSD 中,该功能的核心是视图数据,视图数据包括视图的层次、属性等。本文描述视图数据的组织方式。
图1 HttpServerDebug 视图调试
在进行视图调试时,需要以不同的方式访问这些视图,如图1所示。区域1和区域2需要以顺序的方式访问视图,依次显示。区域3需要以树状访问,描述目标视图在视图层级中的位置。
数据结构
按前文分析,数据结构的设计需要同时利于顺序和树状访问。下图是一个示例。
图2 视图数据与对应的视图
视图数据以数组方式存储,支持 O(1) 复杂度的访问。
以深度优先搜索方法遍历视图层级,每个访问到的视图依次成为数组中的元素。每个元素对象除了包含视图自身基本信息,如位置、背景色等,还需要包含其在整个视图层级中的位置的信息,这个信息通过 parent 和 children 字段实现。
parent 指向对应视图的父视图,值为父视图在视图数据数组中的下标。除了根节点,每个视图有1个父视图。
children 保存对应视图的子视图,只记录直接关联的子视图。每个视图有0个或多个子视图,children 使用数组存储,元素值为子视图在视图数据数组中的下标。
代码实现
构造数据:
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
| + (NSArray *)fetchAllViewsDataInHierarchy { NSMutableArray *allViewsData = [[NSMutableArray alloc] init]; NSArray *windows = [self fetchAllWindows]; for (UIWindow *window in windows) { if (![window isHidden]) { NSMutableDictionary *viewData = [[self fetchViewData:window] mutableCopy]; [viewData setObject:@(-1) forKey:@"parent"]; [viewData setObject:[@[] mutableCopy] forKey:@"children"]; [allViewsData addObject:viewData];
NSInteger viewIndex = [allViewsData count] - 1; NSArray *subviewsData = [self allRecursiveSubviewsInView:window viewData:viewData viewIndex:viewIndex]; [allViewsData addObjectsFromArray:subviewsData]; } } return allViewsData; }
+ (NSArray *)allRecursiveSubviewsInView:(UIView *)superView viewData:(NSMutableDictionary *)superViewData viewIndex:(NSInteger)superViewIndex { NSMutableArray *viewsData = [[NSMutableArray alloc] init]; for (UIView *view in superView.subviews) { if (![view isHidden]) { NSMutableDictionary *viewData = [[self fetchViewData:view] mutableCopy]; [viewData setObject:@(superViewIndex) forKey:@"parent"]; [viewData setObject:[@[] mutableCopy] forKey:@"children"]; [viewsData addObject:viewData];
NSInteger currentIndex = superViewIndex + [viewsData count]; NSArray *subviewsData = [self allRecursiveSubviewsInView:view viewData:viewData viewIndex:currentIndex]; [viewsData addObjectsFromArray:subviewsData];
NSMutableArray *children = [superViewData objectForKey:@"children"]; [children addObject:@(currentIndex)]; [superViewData setObject:children forKey:@"children"]; } } return viewsData; }
+ (NSArray *)fetchAllWindows {}
+ (NSDictionary *)fetchViewData:(UIView *)view {}
|