OC从入门到精通-2.三大特性(封装,继承,多态)

来源:互联网 发布:js 控制class active 编辑:程序博客网 时间:2024/06/13 07:30

OC三大特性

  • 封装
  • 继承
  • 多态

封装

set和get方法

成员变量命名规范

弱语法

类方法的使用

self的一些用法

用法1:self用来访问成员变量

//先看一段没使用self的代码#import <Foundation/Foundation.h>@interface Person : NSObject{    int _age;}- (void)setAge;- (void)age;- (void)test;@end@implementation Person- (void)setAge:(int)age{    //_age是成员变量    _age=age;}- (int)getAge{    return _age;}- (void)test{    int _age=20;  //这是一个局部变量    NSLog(@"成员变量_age的值为%d",_age);}@endint main(int argc, const char * argv[]) {    Person *p=[Person new];    [p setAge:10];    [p getAge];    [p test];    return 0;}

输出结果为:

2016-03-25 11:43:15.326 3-25-3[39932:2019323]成员变量_age的值为20Program ended with exit code: 0

修改上述test方法的代码,如下

- (void)test{    //self :指向调用它的指针    int _age=20;  //self->age用来调用当前对象的成员变量,局部变量不会影响它    NSLog(@"成员变量_age的值为%d",self->_age);}

输出结果为:

2016-03-25 11:45:36.209 3-25-3[39942:2021207] 成员变量_age的值为10Program ended with exit code: 0

//self :指向调用它的指针

2.self用来访问对象方法 or 类方法

//self的使用#import <Foundation/Foundation.h>@interface Person : NSObject{    int _age;}- (void)setAge:(int)age;- (int)age;- (void)test;- (void)eat;- (void)run;@end@implementation Person- (void)setAge:(int)age{    //_age是成员变量    _age=age;}- (int)age{    return _age;}- (void)eat{    NSLog(@"先吃饭");}- (void)run{    [self eat];  //可以调用其他对象方法 or 类方法    NSLog(@"后跑步");}- (void)test{    //int _age=20;    NSLog(@"成员变量_age的值为%d",self->_age);}@endint main(int argc, const char * argv[]) {    Person *p=[Person new];    [p run];    return 0;}

输出结果:

2016-03-25 11:50:16.441 3-25-self2[39968:2024515] 先吃饭2016-03-25 11:50:16.442 3-25-self2[39968:2024515] 后跑步Program ended with exit code: 0

3.self指向调用它的指针,本身就是一个指针

下面来看一段代码,估计下它的输出结果是什么

//self的使用#import <Foundation/Foundation.h>@interface Person : NSObject{}- (void)test;+ (void)test;- (void)test1;+ (void)test1;- (void)rest1;+ (void)rest2;@end@implementation Person- (void)test{    NSLog(@" - test");}+ (void)test{    NSLog(@" + test");}- (void)test1{    [self test];  //-test}+ (void)test1{    [self test];  //+test}@endint main(int argc, const char * argv[]) {    Person *p =[Person new];    [p test1];    return 0;}

输出为:

- test

这里的[p test1]中的p是一个Person对象,所以首先调用 - test1 对象方法,- test1 对象方法中的self 指向的是调用它的指针,也就是对象p,所以self 就会调用- test() 对象方法

如果把上述main 方法修改如下:

int main(int argc, const char * argv[]) {    //Person *p =[Person new];    //[p test1];    [Person test1];

输出则为:

+ test

这里的[Person test1]中的Person是一个类,所以首先调用 + test1 类方法,+ test1 类方法中的self 指向的是调用它的指针,也就是类Person,所以self 就会调用+ test() 类方法

2.继承

类A继承类B,则类B的所有属性,类A都将获得。

继承的基本语法

////  main.m//  继承1#import <Foundation/Foundation.h>//父类 People类,代表所有人类@interface People : NSObject{    int _age;    double _weight;}- (void)setAge:(int)age;- (int)age;- (void)setWeight:(double)weight;- (double)weight;@end@implementation People- (void)setAge:(int)age{    _age=age;}- (int)age{    return _age;}- (void)setWeight:(double)weight{    _weight=weight;}- (double)weight{    return _weight;}@end/****Student****///Student 继承了People,相当于拥有了People里的所以成员变量和方法@interface Student : People@end@implementation Student@end/****Teacher****/@interface Teacher : People@end@implementation Teacher@endint main(int argc, const char * argv[]) {    Student *s=[Student new];    [s setAge:20];    NSLog(@"The age of Student is %d", [s age]);    Teacher *t=[Teacher new];    [t setWeight:50.2];    NSLog(@"The age of Teacher is %f", [t weight]);    return 0;}

输出结果为:

The age of Student is 20The age of Teacher is 50.200000

子类继承父类,那么子类可以访问父类的所以成员变量和方法。

类的继承关系
上图显示的正是代码中的类继承关系。这不是标准的类图,该图主要是帮助理解,箭头所指的是继承关系。继承后,子类拥有父类的方法。所以在Student 和Teacher方法中没有写任何方法,却可以调用set 和get 方法。

继承中的成员变量

对上面代码的Student 作如下修改

@interface Student : People int _age; int _num;@end

运行时会报错!将其注释//int age是可以运行的。
可以看出
- OC中不允许子类和父类有相同的成员变量
- OC中子类可以添加父类中没有的成员变量或方法

继承中的方法

优先检查子类中重写的方法,如果没有再检查父类中的方法

看如下代码:

////  main.m//  继承1#import <Foundation/Foundation.h>//父类 People类,代表所有人类@interface People : NSObject{    int _age;    double _weight;}- (void)run;@end@implementation People- (void)run{    NSLog(@"People在跑");}@end/****Student****///Student 继承了People,相当于拥有了People里的所以成员变量和方法@interface Student : People//定义自己的run方法//父类中已经有了run方法了,所以这里就是“重写”父类方法- (void)run;@end@implementation Student- (void)run{    NSLog(@"Student在跑");}@endint main(int argc, const char * argv[]) {    Student *s=[Student new];    [s run];    return 0;}

输出结果为:

Student在跑Program ended with exit code: 0

优先检查子类中重写的方法,如果没有再检查父类中的方法
其实这个过程很好理解,每个对象里面有一个isa指针,指向它的类,而每个类里面也有一个superclass指针,指向它的父类。
当执行[s run];首先通过s 对象的isa指针指到Student类,在类中寻找run方法,一旦找到就执行。
如果没有找到的话,就会通过superclass指针寻找父类中的run方法,知道找到为止,找不到的话程序会报错。
类继承深层理解

继承的使用场合

  1. 多个类有相同的属性和方法的时候,最好使用一个父类将公有属性和方法集中起来,便于子类的重用。子类继承这个父类就可以了
  2. 但是,大量使用继承会导致耦合性较高,类和类之间的依赖太强。必须要符合逻辑的依赖关系,才使用继承。
  3. 当B类完全拥有A类的属性和方法时,可以使B继承A

继承和组合的区别

下面看一段代码:

////  main.m//  继承1#import <Foundation/Foundation.h>//父类 People类,代表所有人类@interface People : NSObject- (void)run;@end@implementation People- (void)run{    NSLog(@"People在跑");}@end/***Score***/@interface Score : NSObject{    int value;}- (int)value;@end@implementation Score- (int)value{    return  value;}@end//继承:xx是xxx//组合:xxx拥有xxx/****Student****/@interface Student : People{    //这里Student则是拥有的Score类里的所有属性和方法了    //组合    Score *_score;}- (void)run;@end@implementation Student- (void)run{    NSLog(@"Student在跑");}@endint main(int argc, const char * argv[]) {    return 0;}

上面的代码显示,不使用继承也可以获取另一个类的所有方法和属性。这就是组合。从逻辑关系上score明显不适合被继承,Student又想拿到该类的所有内容,所以使用组合是不错的解决方法。

super关键字

////  main.m//  继承1#import <Foundation/Foundation.h>//父类 People类,代表所有人类@interface People : NSObject- (void)run;@end@implementation People- (void)run{    NSLog(@"People准备奔跑!!!");}@end/****Student****/@interface Student : People{}- (void)run;@end@implementation Student- (void)run{    [super run]; //直接调用父类的方法    NSLog(@"Student在跑");}@endint main(int argc, const char * argv[]) {    Student *s=[Student new];    [s run];    return 0;}

输出结果:

 People准备奔跑!!! Student在跑Program ended with exit code: 0

Super关键字可以使子类方法直接调用父类方法
Super不仅可以调用对象方法,还可以调用类方法
Super具体是调用类方法还是对象方法是看Supe所在环境

代码如下:

#import <Foundation/Foundation.h>//父类 People类,代表所有人类@interface People : NSObject- (void)run;+ (void)run;@end@implementation People- (void)run{    NSLog(@"-People准备奔跑!!!");}+ (void)run{    NSLog(@"+People准备奔跑!!!");}@end/****Student****/@interface Student : People{}- (void)run;+ (void)run;@end@implementation Student- (void)run{    [super run]; //直接调用父类的方法    NSLog(@"Student在跑");}+ (void)run{    [super run]; //直接调用父类的方法    NSLog(@"Student在跑");}@endint main(int argc, const char * argv[]) {    [Student run];    return 0;}

3.多态

多态:字面指多种状态
父类指针指向子类对象

////#import <Foundation/Foundation.h>//父类 People类,代表所有人类@interface People : NSObject- (void)run;@end@implementation People- (void)run{    NSLog(@"People奔跑");}@end/****Student****/@interface Student : People{}- (void)run;@end@implementation Student- (void)run{    NSLog(@"Student奔跑");}@endint main(int argc, const char * argv[]) {    //多态:父类指针指向子类对象    People *p = [Student new];    [p run];    return 0;}

输出结果为:

Student奔跑

为什么要用多态?
比如现在有个People类,还有两个子类Student ,Teacher继承这个People类

//父类 People类,代表所有人类@interface People : NSObject{    @public    int age;}@end@implementation People@end/****Student****/@interface Student : People@end@implementation Student@end/****Teacher****/@interface Teacher : People@end@implementation Teacher@end

定义一个函数,用来对Student和Teacher的age赋值,由于它们是两个类,至少需要两个函数

void setAge1(Student *p){    p->age=20;}void setAge2(Teacher *p){    p->age=20;}

下面引入多态的概念,函数直接改成这样,使用一个函数就可以实现多个函数的功能,增加了重用

//如果函数的参数是一个父类类型,则可以传入父类,子类对象void setAge(People *p){    p->age=20;}int main(int argc, const char * argv[]) {    //多态:父类指针指向子类对象    People *p = [Student new];    setAge(p);   //这样就是设置Student的对象的age    return 0;}
0 0