一、分类
1、作用:可以给某一个类扩充一些方法(不修改原来类的代码)。
格式:
@interface 类名 (分类名称)
@end
@implementation 类名(分类名称)
@end
2、优点:一个庞大的类可以分模块开发,可以由多人来编写。3
3、分类注意点
1>分类只是增加方法不能增加成员变量;
2>分类方法实现中可以访问原来类中的成员变量(主类声明,分类实现);
3>分类的方法调用,先去分类中找,然后去原来类中找,最后再到父类中找。
4>分类可以重新实现原来类中的方法,但是会覆盖原来的方法,导致原来的方法无法再使用。
5> 多个Category中如果实现了相同的方法,只有最后一个参与编译的才会有效。
6>方法调用优先级:分类——>原来类——>父类。eg:
<span style="font-size:14px;">#import<Foundation/Foundation.h> @interface NNString (Number) +(int)numberCountOfString:(NNString *)str; @end @implementation NNString(Number) +(int)numberCountOfString:(NNString *)str { int count =0; for (int i=0;i<str.length;i++) { if(i>='0'&&i<='9') count++ } return count; } @end int main() { int n = [NNString numberCountOfString:@"abc123"; NSLog("该字符串中数字个数为:%d",n); return 0; } </span>
二、类本质:类是由某种类型创造出的一个对像 - > class类型创造出的对象
每个类在内存中只是一个类对象,且类对象由class类型创建。
1> 类本身也是一个对象,是”Class“类型的对象,简称”类对象“。
2> 类名就代表着类对象,每个类只有一个类对象。
获取类对象的两种方式:eg:针对Person类的解释
利用Class类 创建Person类对象,然后利用Person类对象创建Person类型的对象(实例对象)
Class -> Person类对象 -> 具体的实例对象、Class类对象->Person类对象->Person类型对象。
Class c = [Person class]; //类方法
或者:
Person *p = [Person new];
Class c = [p class]; //对象方法
3>类对象调用类方法
Class c = [Person class];
person *p = [c new];+load和+initialize
1、类的加载(+load)
1> 加载顺序:父类—>子类
2> 在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法。
3> +(void)load;//程序一启动的时候,就只调用一次此方法,+load方法存在于NSObject中。2、类的初始化(+initialize)
1> 加载顺序:父类—>子类
2> 当第一次使用某个类的时候,就会调用一次+initialize方法,用到的时候才会调用initialize方法,不用的时候不会调用,一个类只会调用一次+initialize方法,而且若调用了子类,父类也会调用一次+initialize方法。
3> +(void)initialize; // 当初始化类时,就会调用此方法,此方法是存在于NSObject。三、description方法
-description:使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出。
1、- description的作用:帮助输出对象,对象输出到屏幕上是什么内容,需要在description里面说清楚。
2、适用场合:当使用NSLog这个函数,并且使用%@来输出对象的时候,会自动调用description方法。<span style="font-size:14px;">int main() { Person *p = [[Person alloc]init]; p.age=20; p.name=@"whbsspu"; NSLog("%@",p);//默认情况下,使用NSLog和%@来输出对象的时候,会调用对象p的-description方法,输出结果为:<类名:内存地址> return 0 }</span>
输出结果:
NSLog的工作原理:当我们使用NSLog这个函数,并且使用%@来输出对象的时候:
1> 首先会调用对象的-description方法;
2> 拿到-description的返回值(NSString *)显示到屏幕;
3> -description方法的默认返回值是<类名:内存地址>。
重写-description方法:对象输出到屏幕上是什么内容,需要在description里面说清楚,怎么说通过重写-description方法来实现。
-(NSString *)description { return [NSString stringWithFormate:@"sge=%d,name=%d",_age,_name]; }
注意:如果在-description方法中使用NSLog打印self。
+description :使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出.
默认情况下输出类名:<span style="font-family:Microsoft YaHei;font-size:14px;">int main() { Class *p = [Person Class]; // 1、调用类的description方法; // 2、拿到description方法的返回值(NNString *)返回到屏幕上。 NSLog("%@",p); }</span>
四、SEL(对方法的包装)
类对象中的每个方法都有一个SEL类型的对象。当第一次调用方法时,会将所有方法从上倒下遍历一次, 当找到我们所需要的方法时,就会根据方法的SEL数据,找到方法地址,最终调用方法。1、 SEL其实是对方法的一种包装,是将方法包装成一个SEL类型的数据,然后根据数据找到对应的方法地址,最后根据地址找到相应的方法,调用方法。即:数据->地址->方法。
所以说发送消息发送的就是SEL类型的数据,就是将方法包装成SEL类型的数据,然后根据SEL类型的数据找到方法地址,根据地址调用方法。2、 方法的调用过程:1> 把方法包装成SEL类型的数据(每个方法都有一个SEL类型数据);2> 根据SEL数据找到对应的方法地址;3> 根据方法地址调用相应的方法。3、SEL数据调用的两种方式:
1> 通过@select将方法转化为SEL数据2> 通过函数将字符串转化为SEL数据SEL s= @selector(test);//利用selector指令创建出test对应的SEL数据数据。 [p performSelector:s];//使用sel调用test方法
4、每个方法内部都有一个隐藏的SEL数据:_cmd。_cmd代表当前方法。NNString *name = @"test"; SEL s1 = NSSelectorFromString(@"test");//把一个字符数据变成一个SEL类型数据。 [p persormSelector:s1];
1> eg: [p performSelector:_cmd]; // 将当前方法转化为SEL数据;
2> SEL数据是不能直接打印的,只能转换成字符串打印。
eg:
-(void)test { NNString *str = NSStringFromSelector(_cmd);//_cmd代表test }