英汉词典推荐:欧路词典
开发注意:开发中尽量让错误发生在编译时,不要发生在运行时!
类回顾:
属性就是专门储存数据的
属性(成员变量)的命名以下划线开头的好处:可以区分属性和局部变量
super并不是关键字,而是编译器的指令符号:
self的用法:与super相似,调用除了自己以外的父类们的方法(而self则是调用自身坐在的类中的方法)
为什么要用super:如果需要在子类中调用父类的方法可以用super
注意:在当前方法内使用self调用当前方法名的方法会造成死循环,但是super不会(super只会向上级找,终会有停止的时候)
应用场景:重写父类的方法,并且需要保留父类方法中的功能,这种情况使用super
面向对象第三大特性,多态:
多态是指:事物的多种表现形态
编译:在一个父类中使用多态指向子类并调用子类的方法时,编译器会先在这个父类中找有没有声明和实现同名的方法(也就是说:子类必须重写父类的方法),如果没有声明则编译报错(如果只声明没有实现,编译器会报警告),如果有声明和实现则可以进行编译.
运行:运行的时候会按照子类中的方法执行
父类使用多态调用子类特有方法的解决办法:可以通过强制类型转换解决父类调用子类特有方法的问题,如下:
Animal*ani2 = [[Catalloc]init];
Cat*c = (Cat*)ani2;//强制类型转换为Cat类型
[cclamb];//调用Cat中的特有方法
使用多态的优点:提高了代码的拓展性
实例变量(成员变量)的修饰符:
作用域:从出现的位置开始直到遇到下一个修饰符或大括号结束
@public:可以在其他类中访问,也可以在本类中访问,也可以在子类中访问
@private(私有的)(默认情况下,在@implement中定义的属性都是private的(纯私有),而且定义在@implement中定义的私有变量,外界看都看不到,子类也不会拥有):不可以在其他类中访问,可以在本类中访问,不可以在子类中访问(只要继承就会拥有,但是拥有不一定可以访问)
@protected(默认情况下,在@interface中定义的所有的属性都是protected):不可以在其他类中访问,可以在本类中访问,也可以在子类中访问
@package:介于private与public之间,在当前包里就是public类型的,在其他包里就是private类型的
description:
只要使用%@打印对象名称,就会默认调用-的description方法,使用%@打印类对象名称,就是调用+的description方法,想打印对象(或类)的信息就在类中重写description方法,里面写上要打印的内容
建议:在description方法中尽量不要使用self,在description中使用%@打印self会造成死循环
class方法:给类发送class消息就会返回当前类的名字
私有方法的定义:如果方法只有声明,没有实现,就称为这个方法是私有方法(OC中没有真正的私有方法)
@property(重点):
@property是一个编译器指令(与预处理指令一样):编译器会在编译的时候将@proberty替换成某一段代码
注意:4.4之前只可以使用@property代替getter和setter方法的声明
@property的书写规范:@property int age;
@property替代setter-getter声明的方式:
@propertyintage;
- (void)setAge:(int)age;
- (int)age;
//Xcode4.4之前编译器会在编译的时候将第一段代码转换为第二段代码和第三段代码
@synthesize也是一个编译器指令:
@synthesize的书写规范:@synthesize age = _age;
如果synthesize后面只写了age(例如:synthesize age;)那么用户赋值与取值的操作都是针对age的,而不是_age
加强版@property:
Xcode4.4之后@property可以直接生成setter和getter方法的声明和实现
加强版@property的书写规范与普通@property的书写方式相同:
@propertyintage;//这一句代码代替了原来getter-setter的四段代码(两个声明,两个实现),并且同时生成了一个纯私有的变量_age
@property会将值赋给下划线开头的变量(而不是同名变量,与@synthesize有区别)
@property的弊端:他只会生成最简单的getter和setter方法,并不会对传入的数据进行过滤/监控等操作,如果需要对数据进行过滤,那么需要重写setter和getter方法
已有@property已经存在的情况下,重写setter-getter:
只重写setter方法,那么编译器会自动生成一个getter方法,并且自动生成私有变量
只重写getter方法,那么编译器会自动生成一个setter方法,并且自动生成私有变量
但是如果同时重写getter方法和setter方法,那么编译器不会自动生成成员变量!
增强@property这段代码在编译的时候做了三件事:
生成实例变量
生成setter_getter声明
生成setter_getter方法的实现
@property的修饰符:
定义一个属性的完整格式:@property(修饰符) 属性类型 属性名称;
readonly(只读):值生成getter方法,不生成setter方法
readwrite(可读可写):既生成setter方法,也生成getter方法
没有只写的修饰符,如果需要,自己手写
另外还可以在(修饰符)的位置写上重命名的getter方法或setter方法,如下
@property(getter= isMarried)intmarried;//这样定义后,我们仍然可以利用setMarried给_married赋值,但是如果需要取值的话,就需要通过isMarried方法了,而不是married方法
id类型(id类型是一个动态数据类型):
默认情况下所有的数据都是静态数据类型
静态数据类型:在编译的时候就知道这个变量属于什么类型,包含哪些属性和方法,如果访问了不属于自己的方法或属性,那么编译器在编译的时候回报错
动态数据类型:在编译的时候编译器不知道这个变量的真是类型,所以如果这个变量访问了不属于自己的属性或方法,编译器也不会报错
id的本质:id == NSObject *
NSObject *与id的区别:
NSObject * 是一个静态数据类型,id是一个动态数据类型
通过静态数据类型定义变量不可以调用子类特有的方法
动态数据类型在定义变量的时候可以调用子类特有的方法
动态数据类型的弊端:由于动态数据类型可以调用任意一个方法,有可能调用到不属于自己的方法,编译器不会报错,可能导致运行时的错误
id的应用场景:一般用在多态,可以减少代码量,避免调用子类特有方法需要强制类型转换
如何避免动态数据类型引发运行时的错误:一般情况下,如果使用动态数据类型定义一个变量,在调用这个变量的方法之前会进行一个判断,判断当前变量是否能够调用这个方法,例如:
idstu3 = [[Studentalloc]init];//定义一个动态的对象stu3
if([stu3isKindOfClass:[Studentclass]])//判断stu3是否属于Student类或Student类的子类,注意isKindOfClass的返回值是一个BOOL类型,class方法是生成一个类的类对象,例如[Person class]就是生成Person的类对象
{
//表达式
}
idstu3 = [[Studentalloc]init];
if([stu3isMemberOfClass:[Studentclass]])//判断stu3是否属于Student类
{
//表达式
}
扩展:
[PersonisMemberOfClass:[Studentclass]]//判断Person是不是Student的子类
new方法的实现原理:
new: (从今以后不能使用new了)
alloc + init: (建议以后都使用这种方法创建对象,可以统一编码格式)
OC中是伪构造方法
构造方法的用途:用于初始化一个对象
重写init方法必须按照苹果规定的格式写:
使用self初始化父类
判断父类是否初始化成功
成功的话,初始化子类的值
返回地址:return self;
重写init的简化写法(最常用):
- (instancetype)init
{
if(self= [superinit]) {
_cli= [[Clipalloc]init];
}
returnself;
}