Class c = [Person class];
Person *p2 = [c new];
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一 分类
1 什么分类?
有的时候,我们需要对原有的类添加一些功能(方法)作为源类扩展,他的功能是扩展类的能力。这种情况下,OC提供了一种完成上述扩展的机制,就是分类。
使用分类,一个庞大的类可以分模块开发,也可以由多个人来编写,更有利于团队合作。
2 分类的语法
@interface 类名 (分类名称)
// 方法声明
@end
Ø 分类的实现
@implementation类名 (分类名称)
// 方法实现
@end
3 分类使用的注意事项
1>Category可以访问原始类的实例变量,但不能添加变量,只能添加方法。如果想添加变量,可以考虑通过继承创建子类
2>Category可以实现原始类的方法,但不推荐这么做,因为它是直接替换掉原来的方法,这么做的后果是再也不能访问原来的方法
3>一个类,可以拥有多个分类
4>多个Category中如果实现了相同的方法,只有最后一个参与编译的才会有效
5>记住,通过分类添加新的方法来扩展该类,不仅仅会影响该类,还会影响该类所有的子类,因此他的所有的子类都会继承这个分类,而不管这些子类愿意不愿意。
下面代码实现给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数和给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数的工能:
// NSString+Number.h
#import <Foundation/Foundation.h>
@interface NSString (Number)
+ (int)numberCountOfString:(NSString *)str;
- (int)numberCount;
@end
#import "NSString+Number.h"
@implementation NSString (Number)
+ (int)numberCountOfString:(NSString *)str
{
// 1.定义变量计算数字的个数
// int count = 0;
//
// for (int i = 0; i<str.length; i++)
// {
// unichar c = [str characterAtIndex:i];
//
// if ( c>='0' && c<='9')
// {
// count++;
// }
// }
// return count;
return [str numberCount];
}
- (int)numberCount
{
int count = 0;
for (int i = 0; i<self.length; i++)
{
// 取出i这个位置对应的字符
unichar c = [self characterAtIndex:i];
// 如果这个字符是阿拉伯数字
if ( c>='0' && c<='9' )
{
count++;
}
}
return count;
}
@end
二 类的本质
类也是一个对象,是Class类型的对象,简称“类对象”,类名就代表着类对象,每个类只有一个类对象。Class类型的定义如下
typedef struct objc_class *Class;
+load方法和+initialize方法
在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法。因为先加载父类,再加载子类,也就是先调用父类的+load,再调用子类的+load;先加载原始类,再加载分类。并且不管程序运行过程有没有用到这个类,都会调用+load加载。
在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法,一个类只会调用一次+initialize方法,先调用父类的,再调用子类的。
我们可以有一下两种方式获取类对象:
Class c = [Person class]; // 类方法
//另一种方式
Person *p = [Person new];
Class c2 = [p class]; // 对象方法
通过一下方式进行类对象的调用:Class c = [Person class];
Person *p2 = [c new];
三 description方法
默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>,这是因为当使用NSLog和%@时自动会调用对象p的-description方法,拿到-description方法的返回值(NSString *)显示到屏幕上而,-description方法默认返回的是“类名+内存地址”。所以我们可以重写-description或者+description方法达到修改NSLog的默认输出的目的。
特别注意的是,如果在-description方法中使用NSLog打印self,会出现死循环。
下面代码是对description方法进行重写的一个实例:
#import "Person.h"
@implementation Person
- (NSString *)description
{
return [NSString stringWithFormat:@"age=%d, name=%@", _age, _name];
}
// 决定了类对象的输出结果
+ (NSString *)description
{
return @"Abc";
}
@end
四 SEL
SEL是对方法的一种包装,将方法包装成一个SEL类型的数据,去寻找对应的方法地址,找到方法地址后就可以调用方法。也就是说SEL可以代替方法,每个方法有方法名,ID,地址,相同的方法名,ID也一样,正常情况下我们根据方法名找到方法,用SEL方法可以根据ID找到方法。
SEL对象的创建如下方式
SEL s = @selector(test);
SEL s2 = NSSelectorFromString(@"test");
SEL对象的其他用法
// 将SEL对象转为NSString对象
NSString *str = NSStringFromSelector(@selector(test));
Person *p = [Person new];
// 调用对象p的test方法
[p performSelector:@selector(test)];
五 关于NSLog输出
1 __FILE__ :源代码文件名
2 __LINE__ :NSLog代码在第几行
3 _cmd :代表着当前方法的SEL
注意,如下代码会引发死循环
- (void)test {
[self performSelector:_cmd];
}