在之前我们操作对象里的成员变量时候,需要在定义类时,在类的声明里加上 @public
如:
@interface Student : NSObject
{
@public
int age;
int no;
}
可以用指向对象的指针直接操作对象内部的数据,而面向对象思想处理问题时,是要将内部结构不要直接暴露给外界。
这就有了封装的思想
封装:将设置成员变量分装到一个方法中去
好处:
1.让外界不能直接访问,修改成员变量值,保证了,成员变量的安全性
2.隐藏一些内部细节,不让外界知道,比如赋值操作
执行封装的方法有set方法和get方法
如:
@interface Student : NSObject
{
int age;
int no;
}
/ /set方法的声明
- (void)setAge:(int)newAge;
@end
@implementation Student
// set方法的实现
- (void)setAge:(int)newAge // 提供一个方法给外界设置
{
if (newAge <= 0) { //对传递进来的参数进行过滤
newAge = 1;
}
age = newAge;
}
@end
1. set 方法的作用:提供一个方法给外界设置age 属性值
2. set 方法的命名规范
1> 方法名必须以set开头
2> set后面跟上成员变量的名称,成员变量的首字母必须大写
3> 返回值一定是void
4> 一定要接受一个参数,而且参数类型一定和成员变量类型一致
5> 形参名称不能跟成员变量名称一样
如:
@interface Student : NSObject
{
int age;
int no;
}
//get方法声明
- (int)age;
@end
@implementation Student
//get方法实现
- (int)age
{
return age; // 返回 成员变量age
@end
1.get方法的作用:返回对象内部的成员变量
2.get方法的命名规则:
1> 肯定有返回值,返回值类型肯定与成员变量类型一致
2> 方法名跟成员变量名一致
3> 不需要接受任何参数
当成员变量只读的时候,可不提set方法
一定要以下划线 _ 开头
好处
1.让get方法名和成员变量名区分开来
2.让成员变量和局部变量区分开来。 一看到 _开头,一般都是成员变量
如:
#import
typedef enum{
Sexman,
Sexwomen
} 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
@implementation Student
// sex 的set和get方法的实现
- (void)setSex: (Sex)sex
{
_sex = sex;
}
- (Sex)sex
{
return _sex;
}
// no 的set方法和get方法的实现
- (void)setNo: (int)no
{
_no = no;
}
- (int)no
{
return _no;
}
@end
int main()
{
Student *stu = [Student new];
[stu setSex: Sexwomen];
[stu setNo: 23];
NSLog(@"学生的学号:%d", [stu no]);
NSLog(@"学生的性别:%d", [stu sex]);
}
对象方法
1> 减号开头 - 开头
2> 只能有对象来调用(指向对象的指针)
3> 对象方法中能访问当前对象的成员变量
类方法
1> 加号 + 开头
2> 只能由类(名)来调用
3> 类方法中不能有成员变量(实例变量),即不能访问成员变量,因为这时还没有创建对象
可以允许类方法和对象方法同名
类方法的的好处和使用场合
1> 不依赖于对象,执行效率高,因为直接调用类名进行操作
2> 能用类方法尽量用类方法
3> 场合: 当方法内部不需要使用成员变量时,即可用类方法
1. 类名调用了对象方法
@interface Person : NSObject
//类方法:打印类名
+ (void)printClassName;
- (void)test;
@end
@implementation Person
+ (void)printClassName
{
NSLog(@"这个类名是Person");
}
- (void)test
{
NSLog(@"调用了test函数");
}
@end
int main()
{
Person *p = [Person new];
// 类调用了对象的方法
[Person test];
/*
错误信息 :
warning: class method '+test' not found 这个类方法没有被找到
+[Person test]: unrecognized selector sent to class 一个无法识别的消息传递给了对象
*/
return 0;
}
2. 对象指针调用了类方法
@interface Person : NSObject
//类方法:打印类名
+ (void)printClassName;
- (void)test;
@end
@implementation Person
+ (void)printClassName
{
NSLog(@"这个类名是Person");
}
- (void)test
{
NSLog(@"调用了test函数");
}
@end
int main()
{
Person *p = [Person new];
// 对象指针调用了类方法
[p printClassName];
/*
错误信息 :
warning: instance method '-printClassName' not found 这个对象方法没有被找到
-[Person printClassName]: unrecognized selector sent to instance
一个无法识别的消息传递给了对象
*/
return 0;
}
self 的用途: 谁调用了当前方法,self就代表谁
* self出现在对象方法中,self就代表对象
* self出现在类方法中,self就代表类
1> 概念:指向了当前对象(方法调用者)
2> 在对象方法中,可以利用“self—>成员变量” 访问当前对象内部的成员变量
#import
@interface Person : NSObject
{
int _age;
}
- (void)setAge: (int)age;
- (int)age;
- (void)test;
@end
@implementation Person
- (void)setAge: (int)age
{
//等价表达:self->_age = age;
_age = age;
}
- (int)age
{
return _age;
}
- (void)test
{
//self (本质为指针)指向方法调用者,代表当前对象这里的方法调用者为对象,
int _age = 20;
NSLog(@"Person的年龄是%d岁", self->_age);
}
@end
int main()
{
Person *p = [Person new];
[p setAge:10];
[p test];
return 0 ;
}
3> [self 方法名]; 在对象的方法中调用当前对象的方法 在类的方法中调用当前类的方法
#import
@interface Dog : NSObject
- (void)bark;
- (void)run;
+ (void)test1;
+ (void)test2;
@end
@implementation Dog
// 对象方法
- (void)bark
{
NSLog(@"汪汪汪");
}
- (void)run
{
[self bark]; // 此时self代表对象本身,则 调用的对象方法 bark
//NSLog(@"汪汪汪");
NSLog(@"跑跑跑");
}
// 类方法
+ (void)test1
{
NSLog(@"类方法调用了test1");
}
+ (void)test2
{
[self test1]; // 此时self代表Dog类,则 调用的类方法 test1
}
@end
self使用注意:方法内调用方法本身,会陷入死循环
#import
@interface Dog : NSObject
- (void)bark;
+ (void)test1;
@end
@implementation Dog
// 对象方法
- (void)bark
{
[self bark]; // 方法内用self调用方法本身,会陷入死循环
NSLog(@"汪汪汪");
}
// 类方法
+ (void)test1
{
[self test1]; // 方法内用self调用方法本身,会陷入死循环
NSLog(@"类方法调用了test1");
}
@end
/********Animal的声明*******/
@interface Animal : NSObject
{
int _age;
double _weight;
}
- (void)setAge:(int)age;
- (int)age;
- (void)setWeight:(double)weight;
- (double)weight;
@end
/********Animal的实现*******/
@implementation Animal
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return _age;
}
- (void)setWeight:(double)weight
{
_weight = weight;
}
- (double)weight
{
return _weight;
}
@end
/********Dog*******/
// : Animal 继承了Animal,相当于拥有了Animal里面的所有成员变量和方法
// Animal称为Dog的父类
// Dog称为Animal的子类
@interface Dog : Animal
@end
@implementation Dog
@end
1> 抽取重复代码
2> 建立了类之间的关系
3> 子类可以拥有父类中的所有成员变量和方法
1> 基本上所有类的根类是NSObject
2> 继承的坏处:耦合性太强
子类重新实现父类中的某个方法,覆盖父类以前的做法
注意点:
1> 父类必须声明在子类的前面
2> 子类不能拥有和父类相同的成员变量
3> 调用某个方法时,优先去当前类中找,如果找不到,去父类中找
1> 当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
2> 当A类完全拥有B类中的部分属性和方法时,可以考虑让B类继承A类
A
{
int _age;
int _no;
}
B : A
{
int _weight;
}
// 继承:xx 是 xxx
// 组合:xxx 拥有 xxx
A
{
int _age;
int _no;
}
B
{
A *_a;
int _weight;
}
@interface Score : NSObject
{
int _cScore;
int _ocScore;
}
@end
@implementation Score
@end
@interface Student : NSObject
{
// 组合
Score *_score; // 用组合的方法代替下面两行定义的成员变量
// int _cScore;
// int _ocScore;
int _age;
}
@end
1.直接调用父类中的某个方法
2.super处在对象方法中,那么就会调用父类的对象方法
super处在类方法中,那么就会调用父类的类方法
3.使用场合:子类重写父类的方法时想保留父类的一些行为
/***************僵尸********************/
@interface Zoombie : NSObject
- (void)walk;
+ (void)test;
- (void)test;
@end
@implementation Zoombie
- (void)walk
{
NSLog(@"往前挪两步******");
}
+ (void)test
{
NSLog(@"Zoombie+test");
}
- (void)test
{
NSLog(@"Zoombie-test");
}
@end
/**************** 跳跃僵尸 ***************/
@interface JumpZoombie : Zoombie
+ (void)ceShi;
- (void)ceShi;
@end
@implementation JumpZoombie
+ (void)ceShi
{
[super test]; // 调用父类Zoombie的类方法 test
}
- (void)ceShi
{
[super test]; // 调用父类Zoombie的对象方法 test
}
- (void)walk
{
// 跳两下
NSLog(@"跳两下");
// 直接调用父类的walk方法,代替下面的NSLog(@"往前挪两步----");
[super walk];
//NSLog(@"往前挪两步----");
}
@end
多态:父类指针指向子类对象
1.没有继承就没有多态
2.代码的体现:父类类型的指针指向子类对象
3.好处:如果函数\方法参数中使用的是父类类型,可以传入父类、子类对象
// 如果参数中使用的是父类类型,可以传入父类、子类对象
void feed(Animal *a)
{
[a eat];
}
4.局限性:
父类类型的变量 不能 直接调用子类特有的方法。否则会有警告
必须强转为子类类型变量后,才能直接调用子类特有的方法
#import
/**************** 动物 ***************/
@interface Animal : NSObject
- (void)eat;
@end
@implementation Animal
- (void)eat
{
NSLog(@"Animal-吃东西----");
}
@end
/**************** 狗 ***************/
@interface Dog : Animal
- (void)run;
@end
@implementation Dog
- (void)run
{
NSLog(@"Dog---跑起来");
}
- (void)eat // 子类Dog重写了 父类方法 eat
{
NSLog(@"Dog-吃东西----");
}
@end
// 如果参数中使用的是父类类型,可以传入父类、子类对象
void feed(Animal *a)
{
[a eat];
}
int main()
{
/*
用任意类的类型来定义的变量,都能存储对象,并可以用这个指向该对象的变量,来发送消息,执行该对象的方法
但会生成警告
*/
NSString *d = [Dog new];// incompatible pointer types initializing 'NSString *' with an expression of type 'Dog *'
[d eat]; // class method 'new' is assumed to return an instance of its receiver type('Dog *')
Animal *aa = [Dog new];
// 多态的局限性:父类类型的变量 不能 用来调用子类的方法,否则会有警告
//[aa run]; // 调用方法时会检测对象的真实形象
// 将aa转为Dog *类型的变量
Dog *dd = (Dog *)aa;
[dd run];
/*
// 多种形态
//Dog *d = [Dog new]; // Dog类型
// 多态:父类指针指向子类对象
Animal *a = [Dog new];
// 调用方法时会检测对象的真实形象
[a eat];
*/
return 0;
}
OC中的字符串是以对象的方式来进行存储的。
OC字符串和C语言字符串对比
如:
/*
// 最简单的创建字符串的方式
NSString *str = @"itcast";
char *name = "itcast";
NSLog(@"我在%@上课", str);
NSLog(@"%s", name);
*/
如:
NSString *nameOC =@"哈哈jack";
char *nameC = "哈哈jack";
int sizeOC = [name length]; // length方法算的是字数
int sizeC = strlen(nameC); //strlen函数算的是字符数
NSLog(@"sizeOC = %d",sizeOC); // sizeOC =6
NSLog(@"sizeC = %d",sizeC); // sizeC =8
创建OC字符串的另一种方式:将变量和字符串整合在一起
格式:[NSString stringWithFormat:@"字符串+占位符", 变量]
int age = 23;
int no = 10;
char *name = 'jack';
NSString *newStr = [NSString stringWithFormat:@"My age is %d and no is %d and name is %@", age, no, name];