iOS开发之自定义View的一些坑

96
liangdahong
2017.09.27 23:07* 字数 466

我们做几个简单的例子哈

自定义一个View

View的m文件中有代码如下:

@implementation BMView

- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"init");
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        NSLog(@"initWithFrame");
    }
    return self;
}

@end

使用如下代码:

NSLog(@"new ");
[BMView new];
NSLog(@"\n ");

NSLog(@"alloc init");
[[BMView alloc] init];
NSLog(@"\n ");

NSLog(@"alloc initWithFrame");
[[BMView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
NSLog(@"\n ");

输出如下:

02.165 ViewDemo[32765:1250187] new 
02.165 ViewDemo[32765:1250187] initWithFrame
02.165 ViewDemo[32765:1250187] init
02.166 ViewDemo[32765:1250187] 
 
02.166 ViewDemo[32765:1250187] alloc init
02.166 ViewDemo[32765:1250187] initWithFrame
02.166 ViewDemo[32765:1250187] init
02.166 ViewDemo[32765:1250187] 
 
02.167 ViewDemo[32765:1250187] alloc initWithFrame
02.167 ViewDemo[32765:1250187] initWithFrame

我们发现

  • 使用newalloc init会调用 initWithFrame init方法
  • 使用initWithFrame会只会调用 initWithFrame方法

自定义BMTableView

UITableView1的m文件中有代码如下:

@implementation BMTableView

- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"init");
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        NSLog(@"initWithFrame");
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    if (self = [super initWithFrame:frame style:style]) {
        NSLog(@"initWithFrame style");
    }
    return self;
}

@end

使用如下代码:

NSLog(@"new");
[BMTableView new];
NSLog(@"\n");

NSLog(@"alloc init");
[[BMTableView alloc] init];
NSLog(@"\n");
    
NSLog(@"alloc initWithFrame");
[[BMTableView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
NSLog(@"\n");
    
NSLog(@"alloc initWithFrame style");
[[BMTableView alloc] initWithFrame:CGRectMake(100, 100, 100, 100) style:UITableViewStylePlain];
NSLog(@"\n");

输出如下:

43.615 ViewDemo[32847:1259789] new
43.637 ViewDemo[32847:1259789] initWithFrame style
43.637 ViewDemo[32847:1259789] initWithFrame
43.637 ViewDemo[32847:1259789] init
43.638 ViewDemo[32847:1259789] 
43.638 ViewDemo[32847:1259789] alloc init
43.639 ViewDemo[32847:1259789] initWithFrame style
43.639 ViewDemo[32847:1259789] initWithFrame
43.640 ViewDemo[32847:1259789] init
43.640 ViewDemo[32847:1259789] 
43.640 ViewDemo[32847:1259789] alloc initWithFrame
43.641 ViewDemo[32847:1259789] initWithFrame style
43.641 ViewDemo[32847:1259789] initWithFrame
43.642 ViewDemo[32847:1259789] 
43.642 ViewDemo[32847:1259789] alloc initWithFrame style
43.642 ViewDemo[32847:1259789] initWithFrame style

我们发现

  • 使用newalloc init会调用 initWithFrame style initWithFrame init方法
  • 使用initWithFrame会调 initWithFrame style initWithFrame方法
  • 使用initWithFrame style会只会调用 initWithFrame style 方法

why

为什么我们只是单纯的调用了 new 或者 init 就会跑到了各种构造方法中呢?感觉有一些奇怪,其实是见怪不怪。我们可以通过Chameleon查看UIViewUITableView的底层实现便一目了然。

UIView.m

UIViewm文件中可看到如下代码UIView.m

- (id)init
{
    return [self initWithFrame:CGRectZero];
}

- (id)initWithFrame:(CGRect)theFrame
{
    if ((self=[super init])) {
        // ...
    }
    return self;
}

UITableView.m

UITableViewm文件中可看到如下代码: UITableView.m

- (id)initWithFrame:(CGRect)frame
{
    return [self initWithFrame:frame style:UITableViewStylePlain];
}

- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)theStyle
{
    if ((self = [super initWithFrame:frame])) {
        // ...
    }
    return self;
}

看到源码后当然就一目了然了,所以我们在自定义一些UI控件时不要盲目的重写各种构造方法,感觉好高大上,其实就是一个大坑😀,之前博主也踩过😭(可能是我孤陋寡闻了)。感谢团队中阿海的指出。随便提醒下,我们可以通过https://github.com/BigZaphod/Chameleon知道天天使用的UITableView为什么那么纵享丝滑,或者各种好玩的东西。

参考

声明

感谢收看,有任何疑问和建议可在下方留言(如果不显示评论,搭个梯子就有了),欢迎GithubStar😁,本文发布于梁大红的技术Blog,转载注明出处即可。

iOS开发