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);
}
@end
int 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的值为20
Program 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的值为10
Program 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);
}
@end
int 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
}
@end
int 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
@end
int 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 20
The 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在跑");
}
@end
int 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方法,知道找到为止,找不到的话程序会报错。
继承的使用场合
- 多个类有相同的属性和方法的时候,最好使用一个父类将公有属性和方法集中起来,便于子类的重用。子类继承这个父类就可以了
- 但是,大量使用继承会导致耦合性较高,类和类之间的依赖太强。必须要符合逻辑的依赖关系,才使用继承。
- 当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在跑");
}
@end
int 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在跑");
}
@end
int 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在跑");
}
@end
int 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奔跑");
}
@end
int 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;
}