iOS查看子视图

iOS遍历打印所有子视图

有时我们想看一下系统的view比如导航条的子视图结构,可以用下面的代码来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 递归获取子视图
- (void)getSub:(UIView *)view andLevel:(int)level {
NSArray *subviews = [view subviews];
// 如果没有子视图就直接返回
if ([subviews count] == 0) return;
for (UIView *subview in subviews) {
// 根据层级决定前面空格个数,来缩进显示
NSString *blank = @"";
for (int i = 1; i < level; i++) {
blank = [NSString stringWithFormat:@" %@", blank];
}
// 打印子视图类名
NSLog(@"%@%d: %@", blank, level, subview.class);
// 递归获取此视图的子视图
[self getSub:subview andLevel:(level+1)];
}
}

打印导航条

1
2
// 打印所有子视图
[self getSub:self.navigationController.navigationBar andLevel:1];

OC中load方法和initialize方法的异同

+load

首先,load方法是一定会在runtime中被调用的,只要类被添加到runtime中了,就会调用load方法,所以我们可以自己实现laod方法来在这个时候执行一些行为。

而且有意思的一点是,load方法不会覆盖。也就是说,如果子类实现了load方法,那么会先调用父类的load方法,然后又去执行子类的load方法。同样的,如果分类实现了load方法,也会先执行主类的load方法,然后又会去执行分类的load方法。所以父类的load会执行很多次,这一点需要注意。而且执行顺序是 类 -> 子类 ->分类。而不同类之间的顺序不一定。

+initialize

与load不同的是,initialize方法不一定会执行。只有当一个类第一次被发送消息的时候会执行,注意是第一次。什么叫发送消息呢,就是执行类的一些方法的时候。也就是说这个方法是懒加载,没有用到这个类就不会调用,可以节省系统资源。

还有一点截然相反,却更符合我们预期的就是,initialize方法会覆盖。也就是说如果子类实现了initialize方法,就不会执行父类的了,直接执行子类本身的。如果类别实现了initialize方法,也不会再执行主类的。所以initialize方法的执行覆盖顺序是 子类类别 -> 子类 -> 父类类别 ->类。且只会有一个initialize方法被执行。