------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1. self和super
1) OC中的self,相当于C++、java中的this指针
2) super用来调用父类的方法
2. self用在对象方法中
self指代的是调用当前方法的对象
3. self用在类方法中
[对象 class];返回的实质就是当前类(类对象)
self指代的是当前类,不能调用对象方法。
4. self修饰变量
1) 函数内部定义和全局变量同名的变量,则局部变量会屏蔽全局变量的作用域。
2) self修饰变量来访问实例变量,不加self访问的是局部变量。self->_name;
5. 类的继承和派生
1) 基类的私有属性不能被访问
2) OC中的继承是单继承
6. 方法的重写
1) 把父类已经实现的方法在子类中重新实现一遍,称为对父类方法的重写。
2) 不用再在子类中声明,只要实现就行
7. 继承的注意事项
1) 子类不能定义和父类同名的变量,但是可以继承父类的变量
2) OC中只支持单继承
3) OC中支持多层继承
4) 继承体系中方法的调用顺序:本类—>父类—>父父类—>….-->NSObject
8. 实例变量的修饰符
1) public 所有类都可以访问
2) protected 只能在当前类和子类中被访问
3) private 只有当前类可以访问
4) 在@interface和@end之间声明的变量默认是@protected
5) 一个类继承了另一个类,那么就拥有了父类的所有成员变量和方法,注意所有的成员变量它都拥有,只是有的不能直接访问
6) 面试题:
① 子类是否可以继承父类中被@private修饰的实例变量
可以,子类可以继承父类的所有实例变量和方法
② 子类是否可以访问父类中被@private修饰的实例变量
子类不能访问父类中被@private修饰的实例变量和方法
9. OC中的私有变量
1) 在.m文件中定义的成员变量是纯私有的,只能在当前类中使用,不能被其他类继承和访问
10. OC中的私有方法
1) 在.h中没有声明,在.m中实现的方法为私有方法。
2) .h文件对外相当于一个接口,声明了哪些东西,其他文件就可以使用哪些东西,没声明的不能用。
3) 私有方法不能被继承
11. description方法
1) 当我们以%@的格式,打印对象时,此时调用对象的description方法
2) 如果当前对象中没有重写description方法,则调用父类的description方法,也就是说打印出对象的地址。
3) 重写description方法时,如果调用了self,会造成死循环。
12. 多态
1) 概念:不同的对象以自己的方式响应相同名称方法的能力称为多态。
2) 多态的条件:
① 有继承关系、有方法重写。
② 父类的声明变量指向子类对象。
3) 多态的优点:
① 简化了编程接口,允许在类和类之间重用一些习惯性的命名,而不用为每一个新加的函数命名一个新名字。
② 多态使得代码可以分散在不同的对象中,而不用试图在一个函数中考虑到所有可能的对象。
4) 多态的原理和实现:
① 动态绑定:动态类型能使程序直到执行时才确定对向所属类型
② 动态类型绑定能使程序直到执行时才确定要对对象调用的实际方法
③ OC不同于传统程序设计语言,它可以在运行时加入新的数据类型和新的程序模块:动态类型识别,动态绑定,动态加载
④ Id类型:通用指针类型,弱类型,编译时不进行类型检查。
#import <Foundation/Foundation.h>
@interface Animal : NSObject
-(void)run;
@end
#import "Animal.h"
@implementation Animal
-(void)run{
NSLog(@"动物在跑");
}
@end
#import "Animal.h"
@interface Dog : Animal
-(void)eat;
@end
#import "Dog.h"
@implementation Dog
-(void)run{
NSLog(@"狗在跑");
}
-(void)eat{
NSLog(@"狗在吃东西");
}
@end
#import "Dog.h"
@interface BigYellowDog : Dog
@end
#import "BigYellowDog.h"
@implementation BigYellowDog
-(void)run{
NSLog(@"大黄狗在跑");
}
@end
#import <Foundation/Foundation.h>
#import "BigYellowDog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//多态1
//父类指针指向子类对象,可以调用子类的同名方法
Animal *an1 = [Dognew];
[an1 run];
//多态2
//父类指针指向子子类对象,可以调用子子类的同名方法
Animal *an2 =[BigYellowDog new];
[an2 run];
//多态3
Animal *an3 = [Dognew];
//[an3 eat]; //父类不能调用子类的新增方法
[(Dog *)an3 eat]; //可以通过强转为子类类型来调用子类
新增的方法
//非多态
//Animal *an4 =[Animal new];
//[an4 eat];
//[(Dog *)an4 eat];//不具有多态关系,即使强转为子类
类型也无法运行,能够让编译器误认为是可以的,所以可以通过编译
,但是运行时出错。
}
return 0;
}
13. 类的本质
1) 类的本质其实也是一个对象(类对象)
2) 类对象:
① 类对象在程序运行时一直存在
② 类对象是一种数据结构,存储类的基本信息
③ 类对象所保存的信息在程序编译时确定,在第一次使用该类的时候被加载到内存中。
④ 类对象代表类,class代表类对象,类方法属于类对象。
⑤ 如果消息的接收者是类名,则类名代表类对象
⑥ 运行时,所有类的实例都由类对象生成,类对象会把实例的isa的值修改成自己的地址,每个实例的isa都指向该实例的类对象
⑦ 从类对象那里可以知道父类信息、可以响应的方法等
⑧ 类对象只能使用类方法,不能用实例方法
3) 我们所定义的类其实也是一个对象,比如Person *p = [Person new];
Person是一个对象,是Class类型的
4) 类对象的获取
① 通过实例对象获取
Person *p = [Person new];
Class c1 = [p class];
这是通过实例对象p的class方法来得到类对象。
② 通过类名获取
Person *p = [Person new];
Class c2 = [Person class];
这是通过类名Person来得到类对象,这里的c1=c2
14. SEL类型全称为selector,表示方法的存储位置
Person *p = [Person new];
[P test];
寻找方法的过程:
1) 首先把test这个方法名包装成SEL类型的数据;
2) 根据SEL数据找到对应的方法地址
3) 根据方法地址调用相应的方法
4) 注意:在这个操作过程中有缓存,第一次找的时候是一个一个的找,非常耗性能,之后再用到的时候就直接使用
注意:SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去寻找对应的方法地址,找到方法地址后就可以调用方法。这些都是运行时特性,发消息就是发送SEL,然后根据SEL找到地址。
调用方法:
Person *p = [Person new];
//手动把test方法包装成SEL类型
SEL s = @selector(test);
//响应方法
[p performSelector:s];
这两行就相当于[p test];
15. 类对象的存储 细节
对象的实例变量p存放的是堆区中实例对象的地址,然后会找到其中的isa指针,实例对象的isa指针指向堆中的Person类对象的地址,类对象中包含所要找的方法的SEL类型,根据类对象的中isa指针指向代码区的地址,在代码区中找对应的SEL类型就是要调用的方法。