———-android培训、Java培训、iOS培训,期待与您交流———-
一、封装
1. 概念
- 封装的目的:使得对象的实例变量默认只能被当前类的对象方法访问。
一个类的数据只能用该类的方法访问和设置而不能被外部任意存储是面向对象设计的本质。这样做提高了数据的安全性,降低了数据被误用的可能性。
不封装的缺点: 当一个类把自己的属性暴露给外部的时候,那么该类就失去对属性的管理权。
在OC语言中,使用@interface(接口)和@implementation(实现)来处理类:
@interface:顾名思义即接口,是外部数据与内部实现交流的通道
@implementation方法的具体实现,只能通过接口调用。
2. 接口和实现
在不进行封装的情况下,对于设置和访问对象实例变量,唯一的方法就是将实例变量的属性设为公共,然后直接进行赋值。例如构建一个Person类,有实例变量age,并对其进行赋值18如下:
#import <Foundation/Foundation.h>
@interface Person:NSObject
{
@public
int _age;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [Person new];
p->_age = 18;
}
return 0;
}
这样做的缺点在于,程序并不能对age值进行检查,当用户输入一个负数时,也会被直接赋值,然而这与实际情况不符。可以通过封装实现对age赋值之前的检查:
#import <Foundation/Foundation.h>
@interface Person:NSObject
{
int _age;
}
-(void)setAge:(int)age;
@end
@implementation Person
-(void)setAge:(int)age{
if (age>0&&age<150) {
_age = age;
}else{
NSLog(@"请输入正确的值!");
}
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [Person new];
[p setAge:18];
}
return 0;
}
这样就实现了对age赋值之前的合法性检查。并且由于将age改回了private属性,因此不能直接对age赋值而只能通过setAge方法。
同样,对于读取age值,也可以定义一个get方法用于获取age值,在@interface下添加get方法声明:
-(int)Age;
在@implementation下添加get方法的具体实现:
-(int)Age{
return _age;
}
set方法的命名规范:
- 方法名必须以set开头
- Set后面跟上成员变量的名称,首字母大写
- 返回值一定是void
- 一定要接收一个参数,而且参数类型需要和成员变量的类型一致
- 形参名不能和成员变量名一样(苹果官方推荐成员变量名前加_以示区分)
get方法的命名规范:
- 一定有返回值,返回值的类型和成员变量的类型一致
- 方法名和成员变量名一样
- 不需要接收任何参数
使用get/set方法的另一个好处是可以方便的控制成员变量的读写性。对于只读变量,不设置set方法可以使其只能被读取而不能被改写,例如接上例为Person类添加num变量作为序号,序号应该是在对象创建时赋予然后不能改写只能读取,在@interface下添加如下内容:
{
int *_nun;
}
-(instancetype)initWithNum:(int)num;//创建对象时可以直接为num赋值
-(int)num;
在@implementation下添加具体实现:
-(instancetype)initWithNum:(int)num{
if (self = [super init]) {
_num = num;
}
return self;
}
-(int)num{
return _num;
}
这样就可以实现创建Person对象时对num赋值,而之后只能读取不能更改的效果。
二、继承
1.概念和基本使用
继承,就是子类可以获得父类的成员变量和方法。例如有Teacher和Student两个类,他们都有age、sex属性,有eat和walk方法。如果不使用继承,那么每个类都要定义以上实例变量和方法,代码重复,效率不高。可以定义一个Person类作为Teacher和Student的父类,在Person类中定义以上变量和方法,避免代码重复。代码示例如下:
#import <Foundation/Foundation.h>
@interface Person:NSObject
@property int age;
@property NSString *sex;
@end
@interface Teacher : Person
@end
@interface Student : Person
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *stu = [Student new];
stu.age = 19;
Teacher *t = [Teacher new];
t.sex = @"Male";
}
return 0;
}
如上所示,虽然Teacher和Student类没有定义任何变量,却继承了Person的age和sex变量,省去了大量重复代码。
实际上除了变量,方法也是可以继承的,上例中实际上Teacher和Student类不仅继承了Person的实例变量,也继承了实例变量的set/get方法。
2.关于变量作用域的问题
类中定义的成员变量有三种常见的修饰符,用于限定变量的作用范围,分别是@public,@protected和@private。还有一种不常用的@package
- @public (公开的)在有对象的前