继承、初始化方法、便利构造器
今天我们要学习继承 初始化方法 以及遍历构造器 首先我们要理解一些概念性的东西.
继承: 在OC里,继承是单继承的,所谓的单继承就是一个子类继承一个父类,例如我们之前创建的Person类是继承于NSObject的.回顾一下继承的格式
@interface Person : NSObject //在冒号后面是继承的父类. 人继承与NSObject
子类是只能继承一个父类,但父类却可以有多个子类.例如:
@interface Student : Person // 学生继承于Person类
@interface Teacher : Person // 老师继承与Person类 老师,学生都是人类
继承的用处: 可以大大的减轻代码量,同时也将子类所拥有的共性结合到一块了,共有的属性就可以写在父类中,在使用的时候,子类可以直接调用.
例如:人类 老师和学生 他们都会由名字name 性别sex 年龄age等共同的属性,这样就一次性写在父类Person中就可以了.然而子类单独拥有的
属性,就单独的写在自己的类中. 例如老师有工资, 学生交学费 这样不同的属性.
@interface Person : NSObject
{
下面三个实例是老师和学生都共同拥有的,所以写在他们所继承的父类Person里
_name = name;
_sex = sex;
_age = age;
}
@interface Teacher : Person
{
工资是老师单独拥有的属性,所以写在Teacher类中
_salary = salary;
}
@interface Student : Person
{
交学费是学生单独拥有的属性,所以写在student类中
_schooling = schooling;
}
初始化方法:
众所周知,Objective-C是一门面向对象的语言,一般情况下,我们在Objective-C中定义一个类时,总要提供一个初始化方法,一般大家都是这样写的:
- (id)init
{
self = [super init];
if (self) {
执行一些资源、变量的初始化工作
}
return self;
}
这样一段简单的代码,却有很多可以思考的问题:
1、为什么要通过[super init]来调用父类的初始化方法,父类的初始化方法里又执行了什么东西?
首先,我们知道对象继承的概念,一个子类从父类继承,那么也要实现父类的所有功能,这就是is-a的关系,比如说上面提到的老师(Teacher)和
学生(Student)都是人,那么Teacher和Student就都回有Person的特征和功能。所以在子类的初始化方法中,必须首先调用父类的初始化方法,
以实现父类相关资源的初始化。例如我们在初始化Teacher这一对象时,必须先初始化Person类这一对象,并把结果赋予Teacher,以使Teacher
满足Person这一特征。典型的,在iOS下,所有的类都继承于NSObject,而NSObject的init方法很简单,就是return self。当父类的初始化完成
之后,即self不为nil的情况下,就可以开始做子类的初始化了。
2、是否一定要提供初始化方法,是否一定要使用init作为初始化方法?
我们在Objective-C中创建一个对象通常使用
Person *per = [[Person alloc] init];
或者
Person *per = [Person new];
new方法是NSObject对象的一个静态方法,根据apple的文档,该方法实际上就是alloc和init方法的组合,实际上二者是一样的,但 apple还是推
荐我们使用第一种方法,为什么呢?因为使用第一种方法,你可以使用自己定义的init方法来做一些初始化,当然,如果子类没有提供 init方法,自
然调用的就是父类的init方法了。所以说,从安全性的角度来收,作为开发者我们在对象使用之前是一定要对对象进行初始化的,因此在定义类的时
候一定要提供初始化方法。但是否一定要使用init作为方法名呢?答案是不一定。使用init作为方法名只是你重写了NSObject的init方法而已,如果
你自己重新定义一个初始化方法,也是完全可以的,只要你在使用的时候记得调用新定义的初始化方法就可以了。
但是,这种方法从设计角度来看我觉得是不可取的。在可复用性方面会比较差,如果确有必要定义一些接受不同参数的初始化方法,我的建
议是,先定义一个init的公用方法,再到其他方法中调用它,如:
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (id)initWithName:(NSString *)name
{
[self init];
_name = name;
}
- (id)initWithAge:(NSInteger)age
{
[self init];
_age = age;
}
补充:
在面向对象编程中,如果编写一个类而没有包含构造函数,这个类仍能编译并且完全可以正常使用。如果类没有提供显式的构造函数,编译
器会提供一个默认的构造函数给你。除了创建对象本身,默认构造函数的唯一工作就是调用其超类的构造函数。在很多情况下,这个超类是语言框
架的一部分,如java中的 Object类,objective-c 中的NSObject类。
不论是何种情况,在类中至少包含一个构造函数是一种很好的编程实践,如果类中有属性,好的实践往往是初始化这些属性。
——以上摘自《The Object-Oriented Thought Process》 by Matt Weisfeld
Person *per = [[Person alloc] init];//alloc是类方法,init是实例方法,Person alloc创建了一个对象(per),然后调用per对象的init方法进行该对象的初始化.
- [(id)initWithName: (NSString *)name
age: (NSInteger)age
{
if(self = [super init])
//这里不是判断self与[super init]是否相等,而是判断是否可以成功初始化. 而用if判断下,是位了方式self为空的情况
_name = name;
_age = age;
}
+(id)personWithName: (NSString *)name
age:(NSInteger)age
{
id obj = [[Person alloc] initWithName:name age:age];
//设置obj的值
return obj;
}
//调用方法
Person *per = [Person alloc]personWithName:@"Jack" age:30];
//本方法调用了上方+号类方法,也就是便利构造器的初始化方法