一、面向对象和封装
面向对象三大特征:封装、继承、多态。
封装是对象和类概念的主要特性。它是隐藏内部实现,稳定外部接口,可以看作是“包装”。 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
好处:使用更加简单 变量更加安全 可以隐藏内部实现细节 开发速度加快。
苹果官方文档中,有一个配图生动的阐释了封装:
@interface用于给人们显示时间,向外部提供展示以及API接口;@implementation是内部实现,人们不需要知道钟表内部如何运转的,同样开发人员也无需关心类、对象方法是如何实现,只需要调用API方法完成相应功能即可。
二、SET方法
当我们封装好一个对象时,出于安全性考虑,开发人员往往不希望别人能够直接访问自己设计的类中成员变量可以被外界随意的访问。例如,Person类中有一个成员变量age,当用于为age赋值负数的时候,将会产生不可预料的后果,此时开发人员就必须将age这个属性私有化(用@private修饰),然,还要为该属性提供一个外界可访问的方法,以供访问者修改age,那么SET方法就这样诞生了。
SET方法作用:用于设置成员变量值,可以在SET方法中,单方面过滤掉一些不合法、不合理的值,提高系统健壮性。
SET方法命名规范:
1)方法名必须以set开头
2)set后面跟上成员变量名称,且成员变量首字母必须大写;如:setAge
3) 返回值一定是 void
4) 一定要接收一个参数,且该参数类型必须与成员变量类型一致,且该形参最好不要与成员变量同名
SET方法的好处:
1) 不让成员变量暴露在外 ,一定程度上保证了数据的安全性
2)对于用户提交过来的数据进行校验、过滤
代码示例:
SET方法声明部分:
/*
4.设计一个成绩类
* C语言成绩(可读可写)
* OC成绩(可读可写)
* 总分(只读)
* 平均分(只读)
*/
#import <Foundation/Foundation.h>
@interface Score : NSObject
{
int _cScore; // C语言成绩
int _ocScore; // OC成绩
int _totalScore;// 总分
int _averageScoe; // 平均分
}
- (void)setCScore:(int)cScore;
- (void)setOcScore:(int)ocScore;
@end
SET方法实现部分:
@implementation Score
- (void)setCScore:(int)cScore
{
_cScore = cScore;
// 计算总分
_totalScore = _cScore + _ocScore;
_averageScoe = _totalScore/2;
}
- (void)setOcScore:(int)ocScore
{
_ocScore = ocScore;
// 计算总分
_totalScore = _cScore + _ocScore;
_averageScoe = _totalScore/2;
}
@end
运行程序:
#import <Foundation/Foundation.h>
int main()
{
Score *s = [Score new];
[s setCScore:90];
[s setOcScore:100];
[s setCScore:80];
return 0;
}
三、GET方法
上面提到,程序员出了安全性考虑将成员变量私有化,那么在类的设计中,必须提供一个方法供调用者获得相应的成员变量,GET方法随之产生。
GET方法的作用:返回对象内部的成员变量
GET方法命名规范:
1)GET方法名一般与成员变量名一样
2)一定有返回值,且返回类型必须与成员变量一致
3)无需接收任何参数
代码示例(结合SET方法一起):
GET方法的声明部分:
#import <Foundation/Foundation.h>
typedef enum {
SexMan,
SexWoman
} Sex;
@interface Student : NSObject
{/*成员变量的命名规范:一定要以下划线 _ 开头
作用:
1.让成员变量和get方法的名称区分开
2.可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量
*/
int _no;
Sex _sex;
}
// sex的set和get方法
- (void)setSex:(Sex)sex;
- (Sex)sex;
// no的set和get方法
- (void)setNo:(int)no;
- (int)no;
@end
GET方法实现部分:
@implementation Student
- (void)setSex:(Sex)sex
{
_sex = sex;
}
- (Sex)sex
{
return _sex;
}
- (void)setNo:(int)no
{
_no = no;
}
- (int)no
{
return _no;
}
@end
运行程序:
#import <Foundation/Foundation.h>
int main()
{
Student *stu = [Student new];
[stu setSex:SexMan];
[stu setNo:10];
[stu sex];
[stu no];
return 0;
}
注意点:
一个类的设计不一定要为每个成员变量都提供setter方法和getter方法,比如一个成员变量,设计者只想让调用者访问,而不希望被其修改,那么只需要提供getter方法即可,极具灵活性。
四、类方法
1)基本概念
类方法可以由类名来直接调用,无需生成对象。
2) 类方法 VS 对象方法
①对象方法名 以 - 开头,而类方法以 + 开头
②对象方法只能由对象调用,没有对象,对象方法无法被调用, 类方法只能由类直接调用,不能由对象调用
③对象方法能访问成员变量,类方法不能访问成员变量
类方法的好处和使用场合:
1> 不依赖于对象,执行效率高
2> 能用类方法,尽量用类方法
3> 场合:当方法内部不需要使用到成员变量时,就可以改为类方法
可以允许类方法和对象方法同名
代码示例:
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int age;
}
// 类方法都是以+开头
+ (void)printClassName;
- (void)test;
+ (void)test;
@end
@implementation Person
+ (void)printClassName
{
// error:instance variable 'age' accessed in class method
// 实例变量age不能在类方法中访问
//NSLog(@"这个类叫做Person-%d", age);
}
- (void)test
{
NSLog(@"111-%d", age);
//[Person test];
}
+ (void)test
{
// 会引发死循环
//[Person test];
NSLog(@"333");
// 会引发死循环
// /[Person test];
}
@end
int main()
{
//[Person printClassName];
[Person test];
//Person *p = [Person new];
//[p test];
/*
-[Person printClassName]: unrecognized selector sent to instance 0x7fa520c0b370
*/
// 系统会认为现在调用的printClassName是个对象方法
//[p printClassName];
return 0;
}
五、self关键字
self 是一个指针,代表当前的调用者,谁调用了,self就指向谁。
* self 出现在对象方法中,self 就代表对象
* self 出现在类方法中, self 就代表类
self的用途:
1)用self关键字访问成员变量可以区分同名的局部变量
2)使用 [self 方法名] 来调用方法
代码示例:
#import <Foundation/Foundation.h>
@interface Dog : NSObject
- (void)bark;
- (void)run;
@end
@implementation Dog
- (void)bark
{
NSLog(@"汪汪汪");
}
- (void)run
{
[self bark];
//NSLog(@"汪汪汪");
NSLog(@"跑跑跑");
}
@end
int main()
{
Dog *d = [Dog new];
[d run];
return 0;
}