一、 面向对象特性之封装
知识点
1.封装说的是对成员变量的封装和间接访问
2.封装涉及两个对象方法:set方法和get方法
3.好处:①安全隐藏内部细节②set方法监听成员变量的改变 一旦改变就做出相应处理行为(**)
4.什么情况下使用?只读:只提供get方法 不要提供set或用@public,set方法一般都要写。读写:两者都要写
5.封装逐渐成为一种编程规范
命名规范
set方法的命名规范:
1)方法名必须以set开头
2)set后面跟上成员变量的名称并且成员变量的首字母必须大写
3)返回值一定是void
4)一定要接收参数,而且参数类型跟成员变量类型一致
5)形参的名称不能和成员变量一样
get方法的命名规范:
1)肯定有返回值,返回类型和成员变量类型一致
2)方法名和成员变量一样
3)不需要接收参数
代码举例
#import<Foundation/Foundation.h>
typedef enum
{
SexMan,SexWoman
} Sex;
@interface Student:NSObject
{
//@public
int age;
//成员变量命名规范:一定要以下划线 _开头 和get方法的名称区分开; 和局部变量也区分开来了
Sex _sex;
}
//提供一个方法给外界设置age的属性值 引出set方法 对传来的参数进行过滤
- (void)study;
- (void)setAge:(int)newAge;
-(int)age;
- (void)setSex:(Sex)sex;
- (Sex)sex;
@end
@impementation Student
- (void)study
{
NSLog(@“%d岁的学生在学习”,age);
}
//set方法的实现
- (void)setAge:(int)newAge
{
if(newAge<=0)
{
newAge=1;
}
age=newAge;
}
- (int)age
{
return age;
}
- (void)setSex:(Sex)sex
{
_sex=sex;
}
- (Sex)sex;
{
return _sex;
}
@end
int main()
{
Student *stu=[Student new];
//stu->age=20;//阻止不了公共类型的数据赋值,不能过滤不合理的数据 怎么解决呢?(*1)
[stu setAge:-10];//因为此时age不是公共类型的 所以通过方法间接访问
[stu study];
//int age=stu->age;//age是公共类型的时候
int age=[stu age];
[stu setSex:SexMan];
}
//*1去掉public 在set方法里去判断过滤 成员变量尽量不要用@public 【成员变量封装】但是访问是个问题 所以引入get方法
二、 弱语法理解
知识点
1.基于C 编译时只发出警告,不报错 【以上程序都是.m文件】
2.让对象调用不存在的方法(没有经过声明)编译只有警告,但是链接时却没错 ,不过运行时会报错:不能识别消息到实例 (程序自动终结)
unrecognized selector sent to instance 。。。。。
3.有声明,没有实现 编译只有警告,但是链接时却没错 ,不过运行时会报错:找不到实现方法
这表明:OC在运行过程中才会检测对象的类里有没有实现相应的方法(由上2可知)
4.无声明,但有实现 编译只有警告,但是链接时却没错 ,运行也OK [由上2可知] (方法和类 通用 前提是在main函数之前)
要是类 要这样写 @implementation Car:NSObject
@end
5.一旦程序运行时出错,程序就会闪退。
代码举例
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)test;
@end
@implementation Person
- (void)test
{
NSLog(@"哈哈哈");
}
@end
/*
-[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
给Person对象发送了一个不能识别的消息:test
*/
int main()
{
Person *p = [Person new];
// OC是在运行过程中才会检测对象有没有实现相应的方法
[p test];
return 0;
}
三、 类方法注意
知识点
1.类方法 通过类调用的方法 以加号 + 开头
2.与对象方法的区别
1)用对象调用类的方法 可以编译通过,报错:方法未找到 因为对象的方法都是减号 - 开头的
2)用类调用对象的方法 可以编译通过,报错:方法未找到 因为类的方法都是加号 + 开头的
3.类方法和对象方法可以同名
4.类被加载到内存
5.对象方法:只能由对象调用 减号 开头 类方法:只能由类调用 加号 开头
6.类方法不用依赖于对象 所以就不存在成员变量(如果使用了该成员变量 编译会报错:实例变量不能在类方法里被访问)
7.成员变量是实例的变量 , 类里面根本就没有 ,只能被对象访问
8.能用类方法就用类方法,这样执行效率高。当方法内部不需要成员变量时,就可以改为类方法。
9.使用场合:①基本没有任何成员的类叫做工具类,里面的方法基本都是类方法②方便在类中 用类相互调用③可以在对象方法里 调用类的方法
代码举例
#import <Foundation/Foundation.h>
@interface Person:NSObject
+ (void) printClassName;
- (void) test;
@end
@implementation Person
+ (void) printClassName
{
NSLog(@“这个类叫做Person”);
}
- (void) test
{
NSLog(@“这个方法是对象的”);
}
@end
int main()
{
Person *p=[Person new];
[Person printClassName];//提高性能 没创建对象 依然可以调用类的行为方法 省了对象的内存
return 0;
}
四、 self的用法
知识点
1.语法:
1)self 指向当前方法调用者
2)可以利用“self->成员变量名”访问当前对象内部的成员变量
3)[self 方法名]可以调用其他对象方法\类的方法
2.self使用注意
1)在一个方法里使用self 调用自己 必会造成死循环
2)分析代码 要从self当前指向的东西出发去判断
3)函数和方法不一样 函数不需要[]去调用
代码举例
#import<Foundation/Foundation.h>
@interface Person:NSObject
{
int _age;
}
- (void)setAge:(int) age;
- (int)age;
- (void)test;
- (void)test2;
@end
@implementation Person
- (void)setAge:(int) age
{
_age=age;//等效于 self->_age=age;
}
- (int)age
{
return _age;//等效于 self->_age;
}
- (void) test
{
int _age=33;/*语法上就近输出它,但是我硬要输出我的成员变量怎么办呢?1)先赋值给一个变量,用这个变量代替输出
2)用self指针指向方法调用者 self->_age*/
NSLog(@“1Person的年龄%d岁”,_age);
}
- (void) test2
{
[self test];//
NSLog(@“2Person的年龄%d岁”,_age);
}
@end
int main()
{
Person *p=[Person new];
[p setAge:10];
[p test];
}
五、 面向对象特性之继承(组合)
知识点
1.类B继承类A,B就有了A的所有东西,这样就抽取了重复代码,建立了类之间的关系
2.子类可以拥有父类中的所有成员变量和方法
3.基本上所有类的根类都是NSObject
注意点
1.如果子类在父类之前声明和实现 会报错 因为编译器从上到下编译的 所以父类要定义在子类之前
2.可以在父类的基础上扩充自己成员变量和方法:
扩充自己成员变量时 1)不能有和父类有同名的成员变量
所以父类的方法可以只写声明不写实现,实现交给子类(可以不再写对应声明)去实现就好了
3.当子类调用方法,首先在自己的类找,找不到再取去父类找,知道最高层类。
4.子类重新实现父类的某个方法,叫做重写。于是就覆盖了父类的所有行为
5.创建子类的时候 子类和父类都已加载到内存了
6.每个类里都有一个superclass 指针 用来指向父类
7.isa 和 superclass 指针 都是声明在NSObject里的 只有这样 才能保证 每一个对象一旦创建就有一个isa指针
每个类一旦创建就有一个superclass指针
8.耦合性太强:类之间关系很紧密 (这使得 删除一个都导致另一个不能用 弊端)
代码举例
#import<Foundation/Foundation.h>
@interface Animal:NSObject
{
int _age;
double _weight;
}
- (void) setAge:(int)age;
- (int) age;
- (void) setWeight:(int)weight;
- (int) weight;
@end
@implementation Animal
- (void) setAge:(int)age;
{
_age=age;
}
- (int) age
{
return age;
}
- (void) setWeight:(int)weight
{
_weight=weight;
}
- (int) weight
{
return _weight
}
@end
//狗
@interface Dog:Animal//Dog类继承自Animal类
@end
@implemetation Dog
@end
//猫
@interface Cat:Animal//继承了父类Animal所有成员变量和方法
@end
@implemetation Cat
@end
int main()
{
Dog *d=[Dog new];
[d setAge:10];//使用了父类的setAge
NSLog(@“狗的年龄%d”,[d age]);
return 0;
}
继承和组合
1.当两个类拥有相同属性和方法的时候,就可以将相同的东西抽象到一个父类中
2.当A类拥有B类中的部分属性和方法中,就可以考虑让B类继承A类,同时还得考虑A B类之间存在从属关系
3.组合 :继承不成 可以考虑组合 区别:继承 xx 是 xxx ;组合 xxx拥有xxx
4.学生是个成绩 X 学生拥有成绩
继承和组合简单举例
A
{
}
B:A//B继承A
{
}
组合
A
{
}
B
{
A * _a;//B拥有A
}
六、 面向对象特性之多态
知识点
1.多态讲的是 (父类)对象具有(多个子类)多态 (就是多种形态 要想多态 必须有继承 没有继承 没有多态)
【将多个方法合并成一个方法】
3.局限性:Animal *aa=[Dog new]; [aa run];//编译器会检测Animal是否有run 没有就会有警告 但是可以运行
(动态检测出了真实类型)
4.父类类型的变量 不能调用子类特有的方法 ,必须要强制转换下 转换到子类类型
所以 Animal *aa=[Dog new]; [(Dog*)aa run];//强制转换下 就OK了
5.Dog *dd=aa;//(不合理 动物是狗)可以等效于 Dog *dd=(Dog *)aa;//这样就合法了
代码举例
#import<Foundation/Foundation.h>
@interface Animal:NSObject
- (void) eat;
@end
@implementation Animal
- (void) eat
{
NSLog(@“吃东西————”);
}
@end
@interface Dog:Animal
@end
@implementation Dog
@end
@interface Cat:Animal
@end
@implementation Cat
- (void) eat
{
NSLog(@“猫吃东西饿————”);
}
@end
void feed(Dog *d)/*如果也想用这个方法喂猫 直接传猫对象显然不合理 那么怎么办呢??1)在写一样的方法 形参换下
2)直接 把形参 改为 Animal *a */
{
[d eat];
}
int main()
{
//多种类型
Dog *d=[Dog new];//Dog 类型 狗以狗的形态存在
//多态:父类指针指向子类对象 狗以动物的形态存在
Animal *a=[Dog new];//OK
NSObject *n=[Animal new];//OK
NSObject *n2=[Dog new];//OK
[a eat];/*调用的eat是父类的还是子类的呢???真相是调用的是子类的 因为调用时会自动检测对象的真实类型
显然这是a指向对象的真实类型是Dog*/
Cat *c=[Animal new];//动物是猫 但是OC这是弱语法(容错能力强)所以不会报错 但有警告 不提倡这样写
NSString *s=[Car new];//猫是字符串 但是OC这是弱语法 所以不会报错 但有警告 不提倡这样写
feed(d);
}
七、 学习查缺补漏
1.super关键字作用
1.1.直接调用父类中的某个方法
1.2.super处在对象方法中,那么就会调用父类的对象方法
super处在类方法中,那么就会调用父类的类方法
1.3.使用场合:子类重写父类的方法时想保留父类的一些行为
#import <Foundation/Foundation.h>
// 僵尸
@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)haha;
- (void)haha2;
@end
@implementation JumpZoombie
+ (void)haha
{
[super test];
}
- (void)haha2
{
[super test];
}
- (void)walk
{
// 跳两下
NSLog(@"跳两下");
// 走两下(直接调用父类的walk方法)
[super walk];
//NSLog(@"往前挪两步----");
}
@end
int main()
{
//[JumpZoombie haha];
JumpZoombie *jz = [JumpZoombie new];
[jz haha2];
return 0;
}
2.NSString的使用
2.1.@“ddddddd”就是一个NSString类对象
2.2.NSString *str=@“dddd”;//好处 以面向对象的形式处理字符串 获取长度 int size =[str length];
2.3.[str length]返回的是unsigned long 类型的 统计的是字数(包括空格)不是字符数了 一个汉字 一个字母 就是2个
2.4.char *str=“dddd”;//不建议使用
代码举例
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
//char *_name;
NSString *_name;
}
@end
int main()
{
/*
// 最简单的创建字符串的方式
NSString *str = @"iloveios";
char *name = "iloveios";
NSLog(@"我在%@写代码", str);
//NSLog(@"%s", name);
*/
int age = 15;
int no = 5;
NSString *name = @"哈哈jack";
// length方法算的是字数
int size = [name length];
NSLog(@"%d", size);
// 创建OC字符串的另一种方式
NSString *newStr = [NSString stringWithFormat:@"My age is %d and no is %d
and name is %@", age, no, name];
NSLog(@"---- %ld", [newStr length]);
return 0;
}