Files
knowledge-kit/Chapter1 - iOS/1.2.md
2020-02-25 17:46:51 +08:00

173 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 看透构造方法
## 构造方法
* new 方法的内部就是先调用 alloc 方法,再调用 init 方法
* alloc 方法:那个类接受 alloc 消息,那么该方法返回该接受类的对象,并把对象返回
* init 方法是1个对象方法作用初始化对象
* 创建对象的步骤:先使用 alloc 创建1个对象再使用 init 初始化这个对象,才可以使用这个对象
* 使用1个未被初始化的对象是很危险的
* init 方法:作用:初始化对象,为对象赋初始值,叫做构造方法
## 重写init构造方法
* 如果想创建出来的对象的属性值不是默认的初始化值,则需要重写 init 方法
* 重写 init 方法的规范:
* 必须要先调用父类的 init 方法(因为当前类初始化就是通过\`\[父类init\]\`去初始化然后将返回值赋值给self
* 调用 init 方法有可能会失败如果失败直接返回nil
* 判断父类是否初始化成功。如果 `self != nil`,则代表初始化成功
* 如果初始化成功就去初始化当前对象的属性
* 最后返回 self
#### 解惑:
1. 为什么要调用父类的 init 方法?
1. 当前类有 isa 指针,当前类的 isa 指针赋值是通过父类的 init 方法赋值的。
2. 需要保证当前对象的父类属性同时被初始化
2. 重写 init 方法的规范:
```
-(instancetype)init{
if (self = [super init]) {
//todo自定义属性的初始化
}
return self;
}
```
```
//Person
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property NSString* name;
@property int age;
-(void)sayHi;
@end
#import "Person.h"
@implementation Person
-(void)sayHi{
NSLog(@"Hi");
}
-(instancetype)init{
self = [super init];
if (self) {
self.name = @"杭城小刘";
self.age = 22;
}
return self;
}
@end
//测试
Person *p1 = [[Person alloc] init]; //p1.name = "杭城小刘"p1.age =22;
Person *p2 = [Person new]; //p2.name = "杭城小刘"p2.age =22;
```
如果2个类的关系为组合关系且它的一个属性是另一个类的对象那么当该类初始化的时候默认它的属性为 nil那么如何初始化
```
-(instancetype)init{
self = [super init];
if (self) {
self.name = @"lbp";
self.age = 22;
self.pig = [[Pig alloc] init];
}
return self;
}
//测试
Person *p1 = [[Person alloc] init]; //p1.dog != nil
```
## 自定义构造方法
* 现状:虽然每次双肩的对象的属性值不是默认的,但是每次初始化的对象的值都是一样的。
* 需求:每次实例化的对象的属性值由调用者决定
* 解决办法:自定义构造方法
* 自定义构造方法规范:
* 自定义构造方法的返回值为 instancetype
* 方法的命名必须以 initWith 开头
* 方法的实现类似 init 的实现
**注意:此时不能使用 new 来调用。(因为 new 的实现是先 alloc 再 init ,默认 init 的实现是给属性赋默认值)**
```
-(instancetype)initWithName:(NSString *)name andAge:(int)age{
if (self = [super init]) {
self.name = name;
self.age = age;
}
return self;
}
```
```
//Person
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property NSString* name;
@property int age;
-(instancetype)initWithName:(NSString *)name andAge:(int)age;
@end
#import "Person.h"
@implementation Person
-(instancetype)init{
self = [super init];
if (self) {
self.name = @"lbp";
self.age = 22;
}
return self;
}
//不能在构造方法之外给self赋值
//编译器认为只有以initWith开头的方法是构造方法
-(instancetype)initWithName:(NSString *)name andAge:(int)age{
if (self = [super init]) {
self.name = name;
self.age = age;
}
return self;
}
@end
//测试
Person *p1 = [[Person alloc] init];
Person *p2 = [Person new];
Person *p3 = [[Person alloc] initWithName:@"杭城小刘2号" andAge:23];
```
![init](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2017-05-23-5-56-53.png)
![init](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2017-05-23-5-57-08.png)
关于“自定义构造方法必须以 initWith 开头”做个实验
![initwith](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2017-05-23-6-01-29.png)
报错信息很明显:不能在构造方法之外给 self 赋值
因为,编译器认为只有以 initWith 开头的方法是构造方法