1.方法重载问题
OC中不允许方法的重载,也就是不允许两个方法同名.
@interface Student : NSObject
- (void)setAge:(int)age;
//- (void)setAge:(float)age; 方法名相同报错
@end
2.static关键字的使用
/*
static 在OC中得使用
不能用的地方
1) 修饰实例变量
2)修饰方法
能使用的地方:
1)局部变量:在代码块内部定义的变量或者 方法内部定义的变量
和在C语言的函数内部修饰变量作用一样,把局部变量的作用域延长了
2)修饰全局变量
static修饰全局变量,只能在本文件中使用
*/
@interface Person : NSObject
{
//static int _age; static 不能修饰成员变量
}
//- static (void)eat; static 不能修饰方法
+ (void)eat;
@end
static int m = 0;
@implementation Person
+ (void)eat {
static int n = 10;
n += m;
NSLog(@"n = %d",n);
m++;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Class person = [Person class];
[person eat]; // n = 10
[person eat]; // n = 11
[person eat]; // n = 13
}
return 0;
}
3.self的使用
1).self用在对象方法中
指代调用当前方法的对象
@implementation Person
-(void)eat{
_weight += 100; //
NSLog(@"人在吃东西,weight:%.2f",_weight);
//self ----> p
//self 指代的就是 调用当前方法的那个对象
//eat方法执行后,立刻执行run
[self run];
}
-(void)run{
_weight -=10;
NSLog(@"人在疯跑,weight:%.2f",_weight);
}
@end
2).self用在类方法中
指代调用当前方法的类
@implementation Person
+(void)test{
// self 在类方法中的使用 self ----->Person
NSLog(@"+test ---->self:%@",self);
[self eat]; //调用的时 eat的类方法
}
+(void)eat{
NSLog(@"+eat");
}
@end
3)self修饰变量
指代当前对象的成员变量
@implementation Car
-(void)setSpeed:(int) speed{
//self ---- car1
//self->speed 实例变量
//speed 是局部变量
self->speed = speed;
}
-(int)speed{
return speed;
}
@end
4.继承
子类继承了父类后,子类就拥有了父类的成员变量和方法,无需再次声明就可直接使用.
子类在使用父类的方法时,有必要对方法重写,变为更适合子类自己的方法.
子类对父类的方法重写后,想使用父类的方法时,用[super 方法名]来调用.
继承的注意事项:
1)子类不能定义和父类同名的实例变量
2)OC中的类是单一继承,一个类只能继承一个父类
3)OC中得类可以支持多层继承
// 声明一个杰尼龟的类 (父类)
@interface JieNiGui : NSObject
{
int _attack; // 攻击力
}
- (void)setAttack:(int)attack;
// 水枪技能
- (void)shuiQiang;
@end
// 声明一个卡咪龟的类 该类继承了杰尼龟
#import "KaMIGui.h"
@interface KaMIGui : JieNiGui
{
// int _attack; 子类不能定义和父类同名的实例变量
}
@end
@implementation KaMIGui
// 卡咪龟自己的水炮方法
- (void)shuiPao {
NSLog(@"这是卡咪龟的水炮技能");
}
// 卡咪龟对父类的水枪方法进行了重写
- (void)shuiQiang {
NSLog(@"这是卡咪龟的水枪技能 卡咪龟的攻击力为 %d",_attack);
}
@end
// 声明一个水箭龟的类,继承了杰尼龟
#import "ShuiJianGui.h"
//@interface ShhuiJanGui : KaMIGui,JieNiGui OC不支持多继承
@interface ShhuiJanGui : KaMIGui
@end
@implementation ShuiJianGui
// 水箭龟自己的火箭水炮技能
- (void)huoJianShuiPao {
NSLog(@"这是水箭龟的火箭水炮技能");
}
// 重写了卡咪龟的水枪技能
- (void)shuiQiang {
NSLog(@"这是水箭龟的水枪技能,水箭龟的攻击力为 %d",_attack);
}
// 重写了杰尼龟的水炮技能
- (void)shuiPao {
NSLog(@"这是水箭龟的水炮技能,水箭龟的攻击力为 %d",_attack);
}
@end
5.实例变量修饰符的使用
/*
实例变量修饰符(访问控制)
1)@public 共有的,公共的,在任何地方都可以被访问
2)@protected 受保护的,在当前类和他得子类(派生)中使用
这也是默认的
3) @private 私有的,它修饰的实例变量,只能在当前类中使用
实例变量修饰符(访问控制)的作用域
从定义的位置开始,向下遇到另外不同类型的修饰符就结束了
如果没有遇到其他类型的修饰符,此时到实例变量声明的"}"结束
*/
#import <Foundation/Foundation.h>
@interface Animal : NSObject
{
@public //可以在当前类和子类中使用以及其他任何地方都可以使用
int _age;
@protected //可以在当前类和子类中使用
int _speed;
@private //可以被子类继承,但是不能被子类访问
int _color;
}
-(void)eat;
-(void)run;
@end
6.OC中的私有变量(相对)和私有方法(相对)
/*
OC中的私有变量(相对)
如果在.m中定义了变量,则这些变量只能在当前类中使用,不能被子类继承
也不能再子类中可见,当然也不能使用。
OC中的私有方法(相对)
1)特点:只在.m中实现,不在.h中声明
2)一般情况下,我们使用self进行调用
3)如果父类在其他方法中调用了该私有方法,子类可以在这个方法中间接的调用该私有方法
4)该方法一样会被子类继承和重写,前提是在父类的另一个方法间接调用该私有方法和子类知道该私有方法的名称时
*/
// 声明一个Person类作为父类
@interface Person : NSObject
- (void)run;
@end
// 在.m中定义了变量a 不能被子类和其他类使用
int a = 1;
@implementation Person
- (void)personTest {
NSLog(@"这是Person自己的test方法");
}
// 子类通过继承run方法间接地调用了personTest 方法
- (void)run {
[self personTest];
}
@end
// 声明Student类继承Person
#import "Person.h"
@interface Student : Person
- (void)test;
@end
#import "Student.h"
@implementation Student
- (void)test {
//a = 10; 子类中无法访问到父类中的a
}
// 如果知道该方法的名称一样可以在子类中进行重写
- (void)personTest {
NSLog(@"对Person的test方法进行重写");
}
@end
7.description方法的重写
覆盖父类的description方法
如果打印 实例对象 的时候会自动的调用该方法
返回的时一个字符串
默认情况下返回的时<类名:内存地址>
#import "Person.h"
@implementation Person
// 重写description的对象方法
- (NSString *)description {
return [NSString stringWithFormat:@"%@ 年龄为 %d",_name,_age];
}
+ (NSString *)description{
return @"武林马卡齐鲁";
}
@end
8.多态的使用
/*
类和类之间的关系:
1)继承 2)多态
对象和对象的关系:
1)组合 2)依赖 3)关联
多态:
不同的对象以自己的方式,响应同名的方法
多态的条件:
1)存在继承关系
2)存在方法重写 (一定会存在同名方法(父类和子类之间 一定有同名方法))
3)父类声明的指针,指向了子类的对象
*/
#import <Foundation/Foundation.h>
#import "Dog.h"
#import "Cat.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Animal *ani = [Animal new];
// [ani run];
// [ani eat];
//
// Dog *d = [Dog new];
// [d run];
// [d eat];
//多态的使用
//***************** 使用父类访问子类的同名方法 **********
//多态的优点:
// 1) 父类可以访问子类的同名的方法
// 2) 可以延续一些使用习惯
// Animal *ani = [Dog new];
// [ani run];
//多态 动态类型
// 当程序运行的时候,才知道到底是什么类型
// Animal *an2 = [Cat new];
// [an2 eat];
//****************** 使用父类 访问子类的 特有的方法 *******
Animal *an3 = [Dog new];
//an3 实质上存储的时 dog对象的地址
// [an3 eat];
// [an3 run];
//报错的原因:
//an3 Animal 类型的
//编译的时候,检测到Animal 类名根本没有 lookHome
// [an3 lookHome];
[(Dog *)an3 lookHome];
//需要注意:
//此处会报错,因为 an3执行的时候,保存的时dog对象的地址
// dog对象中没有 catchMouse方法
// [(Cat *)an3 catchMouse];
}
return 0;
}
9.类的本质
类的本质是class类型的对象简称类对象
@autoreleasepool {
//获取类对象
Class c1 = [Person class];
//类对象的使用方法:
// Person *p = [Person new];
//1、使用类对象创建实例对象
Person *p = [c1 new];
Person *p1 = [[c1 alloc] init];
[p playGame];
[p1 playGame];
// 2、用类对象 调用类方法
//使用类对象调用 类方法
// c1 等价于 Person
// [Person test];
[c1 test];
//
Class c2 = [p class];
[c2 test];
// c1 = [Dog class];
// c1
}
return 0;
}
10.SEL类型
方法调用的过程就是把方法都封装成SEL类型,当实例变量创建好后就把要调用的方法封装成SEL类型在类对象的方法映射表中,查找,类对象中的SEL类型再去和代码区中的方法一一匹配,找到则返回该SEL的地址.
int main(int argc, const char * argv[]) {
@autoreleasepool {
//把Person中得playGame方法封装成 SEL
//通过一个函数来实现的封装
//此时就把 playGame 手工的封装成了 SEL
//SEL 是一个类型
SEL s1 = @selector(playGame);
//s1
Person *p = [Person new];
//performSelector 作用根据SEL去查找方法,并且执行
[p performSelector:s1];
}
return 0;
}