Objective-c 中如何重写父类的初始化方法
2017-06-28 14:07
447 查看
在我们的日常开发中我们经常会定义一些自己的子类继承一些UIKit 库中的类,那我们应该如何重写的这些初化方法呢?那我们先看看这些类有哪些初初化方法吧。(这里就用UIView为例)
我们先说说这个几个方法的执行顺序吧,init 方法我们知道它是基类NSObject 类中继承过来,应该是最基本的方法了,返回一个自己的对象。initWithCoder 这个是我们用IB初始View来调用的。-initWithFrame方法呢我们暂时先不说先往下看。
有时候我们经常写一些的自定义东西我们想把这些东西开源出去,(当然我们很多时候都在用开源东西)。我们就想写的很完美,我们就会重载所有的初始方法,我们先来定义一个UIView 子类MyView然后重写这些方法
我们先看看在IB中创建一个view 把class 设成MyView 看看方法的调用情况:
1.1.png
我们跑下程序看看输出情况是不是像我们所说的那样:
1.2
输出结果是调用了 initWithCoder.
所以如果我们想让我们的类支持IB我们可以重写这个方法然后初始化一些东西。
下面我们来试试的手动添加的我们先用initWithFrame方法:
我们再来运行一下看看结果:
1.3
也符合我们的预期。那我们来看看最后一种情况了,因为我们现在的项目中越来越多人采用AutoLayout了初始化的时候可能调用下init就完了。不会去调用initWithFrame方法,那我们看看我们在重写了这三个方法后调用init初始化会出现什么情况?我稍加修改一下上面的代码:
看看输出结果是什么?
1.4
奇怪了竟然先输出了initWithFrame ,然后才输出了init
为什么会这样子呢?如果你看过我的上篇文章你就应该懂了,我们可以回到最上面看看发现这个两个方法后面的都有NS_DESIGNATED_INITIALIZER这么一行字。什么意思呢?Objective-C
有指定初始化方法(designated initializer)和间接(secondary initializer)初始化方法的观念。
designated 初始化方法是提供所有的参数,secondary 初始化方法是一个或多个,并且提供一个或者更多的默认参数来调用
designated 初始化的初始化方法。由此我们可以看出init 应该是个secondary initializer 初始方法,当我们调用 [super init] 时候父类应该是去调用designated initializer 方法 initWithFrame 方法。所以我们不应该在我们的类里去重写secondary initializer 方法。如果像这样子都重写了那就会调用两遍我们的setup方法。很显然这样子是没有必要的。同时也会出现问题如果像我们上面那样的写法我们就会添加两个subView到同一个地方,这显然不是我们想要的结果所以我们应该避免这样的情况出现。这里我打下结果出来的可以自已尝试下看看:
1.5
所以当我们定义一个子类时:
不需要重载任何初始化函数(当然这个情况不太常用,我们要初始化一些我们自己东西)
重载 designated initializer(上面的我们只要重写initWithFrame
方法即可,如果要支持IB再重写initWithCoder 就可以了,完全没有必要再去重写init 当然你可以只重写的 init
不重写initWithFrame这样子也不会出现二次调用的问题,但这样子使用者可以使用initWithFrame方法初始化这样子就会导致一些东西会被没有初化)
定义一个新的 designated initializer
以此类推读者可以尝试的看看UIViewController 的。(这篇文章算是上一篇文章的补充吧)。
- (id)init; - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER; - (instancetyp)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER
我们先说说这个几个方法的执行顺序吧,init 方法我们知道它是基类NSObject 类中继承过来,应该是最基本的方法了,返回一个自己的对象。initWithCoder 这个是我们用IB初始View来调用的。-initWithFrame方法呢我们暂时先不说先往下看。
有时候我们经常写一些的自定义东西我们想把这些东西开源出去,(当然我们很多时候都在用开源东西)。我们就想写的很完美,我们就会重载所有的初始方法,我们先来定义一个UIView 子类MyView然后重写这些方法
#import "MyView.h" @implementation MyView{ UIView *subView; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setup]; NSLog(@"初始化-------%@",NSStringFromSelector(_cmd)); } return self; } - (id)init { self = [super init]; if (self) { [self setup]; NSLog(@"初始化-------%@",NSStringFromSelector(_cmd)); } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { NSLog(@"初始化-------%@",NSStringFromSelector(_cmd)); } return self; } - (void)setup { subView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)]; subView.backgroundColor = [UIColor redColor]; [self addSubview:subView]; } @end
我们先看看在IB中创建一个view 把class 设成MyView 看看方法的调用情况:
1.1.png
我们跑下程序看看输出情况是不是像我们所说的那样:
1.2
输出结果是调用了 initWithCoder.
所以如果我们想让我们的类支持IB我们可以重写这个方法然后初始化一些东西。
下面我们来试试的手动添加的我们先用initWithFrame方法:
#import "ViewController.h" #import "MyView.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(10, 20, 100, 100)]; myView.backgroundColor = [UIColor purpleColor]; [self.view addSubview:myView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
我们再来运行一下看看结果:
1.3
也符合我们的预期。那我们来看看最后一种情况了,因为我们现在的项目中越来越多人采用AutoLayout了初始化的时候可能调用下init就完了。不会去调用initWithFrame方法,那我们看看我们在重写了这三个方法后调用init初始化会出现什么情况?我稍加修改一下上面的代码:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. MyView *myView = [[MyView alloc] init]; myView.frame = CGRectMake(10, 20, 100, 100); myView.backgroundColor = [UIColor purpleColor]; [self.view addSubview:myView]; }
看看输出结果是什么?
1.4
奇怪了竟然先输出了initWithFrame ,然后才输出了init
为什么会这样子呢?如果你看过我的上篇文章你就应该懂了,我们可以回到最上面看看发现这个两个方法后面的都有NS_DESIGNATED_INITIALIZER这么一行字。什么意思呢?Objective-C
有指定初始化方法(designated initializer)和间接(secondary initializer)初始化方法的观念。
designated 初始化方法是提供所有的参数,secondary 初始化方法是一个或多个,并且提供一个或者更多的默认参数来调用
designated 初始化的初始化方法。由此我们可以看出init 应该是个secondary initializer 初始方法,当我们调用 [super init] 时候父类应该是去调用designated initializer 方法 initWithFrame 方法。所以我们不应该在我们的类里去重写secondary initializer 方法。如果像这样子都重写了那就会调用两遍我们的setup方法。很显然这样子是没有必要的。同时也会出现问题如果像我们上面那样的写法我们就会添加两个subView到同一个地方,这显然不是我们想要的结果所以我们应该避免这样的情况出现。这里我打下结果出来的可以自已尝试下看看:
1.5
所以当我们定义一个子类时:
不需要重载任何初始化函数(当然这个情况不太常用,我们要初始化一些我们自己东西)
重载 designated initializer(上面的我们只要重写initWithFrame
方法即可,如果要支持IB再重写initWithCoder 就可以了,完全没有必要再去重写init 当然你可以只重写的 init
不重写initWithFrame这样子也不会出现二次调用的问题,但这样子使用者可以使用initWithFrame方法初始化这样子就会导致一些东西会被没有初化)
定义一个新的 designated initializer
以此类推读者可以尝试的看看UIViewController 的。(这篇文章算是上一篇文章的补充吧)。
相关文章推荐
- 【Objective-C编程开发】关于子类重写父类初始化方法的争论
- iOS开发中、如何选择重写初始化方法?
- Objective-C学习笔记(二十二)——初始化方法init的重写与自定义
- 浅析关于ObjectC中的自定义初始化方法和便利构造器以及重写父类的description方法的理解
- [JAVA]重写父类方法并向上转型时的初始化问题
- Objective-C学习笔记(二十二)——初始化方法init的重写与自己定义
- Objective-C的Initialize初始化方法研究
- objective-C中如何判断一个类中有没有定义某个方法
- C#调用父类构造方法(:base())与重写父类方法(virtual/override)
- C#下 子类继承父类的虚方法后 使用override重写父类方法 和 不使用override重写有什么区别?
- Objective-C中的NSObject对象经常使用到的方法-判断父类子类关系
- 子类重写父类方法的访问权限
- Java中的类成员访问控制符和继承重写父类的方法时的类成员访问控制符的相关问题
- 学习C#高级编程--在重写基类的方法中,如何调用基类的函数
- [zz]如何在Python中调用父类的同名方法
- java中父类的静态方法不能被重写
- Objective-C的Initialize初始化方法研究
- 重写父类的方法
- 继承和方法重写如何支持多态性
- 如何:重写 ToString 方法(C# 编程指南)